latex預處理

\( \newcommand{\ord}[1]{\mathcal{O}\left(#1\right)} \newcommand{\abs}[1]{\lvert #1 \rvert} \newcommand{\floor}[1]{\lfloor #1 \rfloor} \newcommand{\ceil}[1]{\lceil #1 \rceil} \newcommand{\opord}{\operatorname{\mathcal{O}}} \newcommand{\argmax}{\operatorname{arg\,max}} \newcommand{\str}[1]{\texttt{"#1"}} \)
顯示具有 acm-icpc live archive 標籤的文章。 顯示所有文章
顯示具有 acm-icpc live archive 標籤的文章。 顯示所有文章

2017年4月27日 星期四

[ uvaLive 5031 ] Graph and Queries

題目:
https://icpcarchive.ecs.baylor.edu/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&category=33&problem=3032

解法:
這題很明顯是名次樹的題目。把所有操作存起來,然後再到著做回來,就可以把刪邊變成增邊。用並查集維護那些點連通,用Treap紀錄那些點的權重,當增加邊的操作造成兩個集合要合併時,使用啟發式合併,總複雜度大約為$\ord{n log n log n}$

我的code中沒有用到任何旋轉的操作,全部都用split和merge完成,證明了只需要會split和merge一樣是可以拿來寫名次樹的

code:
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
#include<bits/stdc++.h>
#define x first
#define y second
using namespace std;
#define MAXN 100005
#define MAXM 1000005
struct node{
    node *l,*r;
    int key;
    unsigned s;
    node(int k):l(0),r(0),key(k),s(1){}
    void up(){
        s=1;
        if(l)s+=l->s;
        if(r)s+=r->s;
    }
};
inline unsigned ran(){
    static unsigned x=time(0);
    return x=x*0xdefaced+1;
}
inline unsigned size(node *o){
    return o?o->s:0;
}
node *merge(node *a,node *b){
    if(!a||!b)return a?a:b;
    if(ran()%(a->s+b->s)<a->s){
        a->r=merge(a->r,b);
        a->up();
        return a;
    }else{
        b->l=merge(a,b->l);
        b->up();
        return b;
    }
}
void split(node *o,node *&a,node *&b,int k){
    if(!o)a=b=0;
    else{
        if(o->key<k){
            a=o;
            split(o->r,a->r,b,k);
        }else{
            b=o;
            split(o->l,a,b->l,k);
        }
        o->up();
    }
}
void insert(node *&o,int k){
    node *a,*b;
    split(o,a,b,k);
    o=merge(a,merge(new node(k),b));
}
void split2(node *o,node *&a,node *&b,unsigned k){
    if(!o)a=b=0;
    else{
        if(k<=size(o->l)){
            b=o;
            split2(o->l,a,b->l,k);
        }else{
            a=o;
            split2(o->r,a->r,b,k-size(o->l)-1);
        }
        o->up();
    }
}
bool erase(node *&o,int k){
    node *a,*b,*c;
    split(o,a,b,k);
    if(!b)return 0;
    split2(b,b,c,1);
    if(b->key==k){
        delete b;
        return o=merge(a,c),1;
    }
    return o=merge(a,merge(b,c)),0;
}
inline int kth(node *&o,int k){
    if((int)size(o)<k||k<1)return 0;
    //注意這裡他會給你不合法的測資,被坑很久
    node *a,*b,*c;
    split2(o,a,c,size(o)-k);
    split2(c,b,c,1);
    o=merge(a,merge(b,c));
    return b->key;
}
struct edge{
    int u,v,use;
    edge():use(0){}
}E[MAXM];
struct XDD{
    char c;
    int p,w;
}g;
vector<XDD> P;
int n,m,t;
int st[MAXN];
int s[MAXN];
int find(int x){
    return st[x]==x?x:st[x]=find(st[x]);
}
node *sa[MAXN];
void dfs(node *&o,node *&x){
    if(!o)return;
    insert(x,o->key);
    dfs(o->l,x);
    dfs(o->r,x);
    delete o;
    o=0;
}
node *strong_merge(node *&a,node *&b){
    if(size(a)<size(b))swap(a,b);
    dfs(b,a);
    return a;
}
int main(){
    int _=0;
    while(scanf("%d%d",&n,&m),n||m){
        for(int i=1;i<=n;++i){
            scanf("%d",&s[i]);
            st[i]=i;
        }
        for(int i=1;i<=m;++i){
            scanf("%d%d",&E[i].u,&E[i].v);
            E[i].use=0;
        }
        P.clear();
        for(char c[10];scanf("%s",c),c[0]!='E';){
            g.c=c[0];
            if(c[0]=='D'){
                scanf("%d",&g.p);
                E[g.p].use=1;
            }else{
                scanf("%d%d",&g.p,&g.w);
                if(c[0]=='C'){
                    swap(s[g.p],g.w);
                }
            }
            P.push_back(g);
        }
        for(int i=1;i<=n;++i){
            sa[i]=new node(s[i]);
        }
        for(int i=1;i<=m;++i){
            int u=find(E[i].u),v=find(E[i].v);
            if(!E[i].use&&u!=v){
                st[u]=v;
                sa[v]=strong_merge(sa[v],sa[u]);
            }
        }
        vector<int> ans;
        for(int i=(int)P.size()-1;i>=0;--i){
            if(P[i].c=='D'){
                int u=find(E[P[i].p].u),v=find(E[P[i].p].v);
                if(u!=v){
                    st[u]=v;
                    sa[v]=strong_merge(sa[v],sa[u]);
                }
            }else if(P[i].c=='Q'){
                ans.push_back(kth(sa[find(P[i].p)],P[i].w));
            }else{
                int p=find(P[i].p);
                erase(sa[p],s[P[i].p]);
                insert(sa[p],P[i].w);
                s[P[i].p]=P[i].w;
            }
        }
        double V=(double)ans.size();
        long long tot=0;
        for(auto i=ans.rbegin();i!=ans.rend();++i)tot+=*i;
        printf("Case %d: %.6lf\n",++_,tot/V);
    }
    return 0;
}

2015年12月30日 星期三

[ UVA ] 1298 - Triathlon

題目:
https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=4044

解法:
假設比賽總長度為1,其中游泳長度x,自行車長度y,賽跑長度1-x-y,則選手i打敗選手j的條件是:
x/v[i] + y/u[i] + (1-xy)/w[i] < x/v[j] + y/u[j] + (1-xy)/w[j]
整理上式得到不等式:
(1/v[j]-1/w[j]-1/v[i]+1/w[i])x + (1/u[j]-1/w[j]-1/u[i]+1/w[i])y + 1/w[j]-1/w[i] > 0

對於每個選手i,都可以得到相對於選手j的如上不等式(不等式在二維坐標係是一個半平面),問題轉化為解n-1個格式為Ax+By+c>0的不等式,即求半平面交,如果半平面交非空,則輸出Yes
因為數字很小且題目要求精度,所以把A、B、C都乘上10000
最後記得加入x>0、y>0、1-x-y>0這三個半平面

code:
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
#include<bits/stdc++.h>
using namespace std;
template<typename T>
struct point{
    T x,y;
    point(){}
    point(const T&dx,const T&dy):x(dx),y(dy){}
    inline const point operator+(const point &b)const{
        return point(x+b.x,y+b.y);
    }
    inline const point operator-(const point &b)const{
        return point(x-b.x,y-b.y);
    }
    inline const point operator*(const T &b)const{
        return point(x*b,y*b);
    }
    inline const point operator/(const T &b)const{
        return point(x/b,y/b);
    }
    inline const T dot(const point &b)const{
        return x*b.x+y*b.y;
    }
    inline const T cross(const point &b)const{
        return x*b.y-y*b.x;
    }
    inline point normal()const{/*求法向量*/
        return point(-y,x);
    }
    inline const T abs2()const{/*向量長度的平方*/
        return dot(*this);
    }
};
template<typename T>
struct line{
    line(){}
    point<T> p1,p2;
    line(const point<T>&x,const point<T>&y):p1(x),p2(y){}
    inline bool parallel(const line &l)const{/*直線平行*/
        return (p1-p2).cross(l.p1-l.p2)==0;
    }
    inline T cross(const point<T> &p)const{/*點和有向直線的關係,>0左邊、=0在線上<0右邊*/
        return (p2-p1).cross(p-p1);
    }
    inline point<T> line_intersection(const line &l)const{/*直線交點*/
        point<T> a=p2-p1,b=l.p2-l.p1,s=l.p1-p1;
        return p1+a*s.cross(b)/a.cross(b);
    }
};
template<typename T>
struct polygon{
    polygon(){}
    std::vector<point<T> > p;
    inline const point<T>& operator[](int id)const{
        return p[id];
    }
    inline static char sign(const T&x){
        return x>=0?1:-1;
    }
    inline static bool angle_cmp(const line<T>& A,const line<T>& B){
        point<T>a=A.p2-A.p1,b=B.p2-B.p1;
        char ay=sign(a.y),by=sign(b.y),ax=sign(a.x),bx=sign(b.x);
        return ay>by||(ay==by&&(ax*ay>bx*by||(ax*ay==bx*by&&a.cross(b)>0)));
    }
    inline int halfplane_intersection(std::vector<line<T> > &s){
        sort(s.begin(),s.end(),angle_cmp);
        int L,R,n=s.size();
        std::vector<point<T> > px(n);
        std::vector<line<T> > q(n);
        q[L=R=0]=s[0];
        for(int i=1;i<n;++i){
            while(L<R&&s[i].cross(px[R-1])<=0)--R;
            while(L<R&&s[i].cross(px[L])<=0)++L;
            q[++R]=s[i];
            if(q[R].parallel(q[R-1])){
                --R;
                if(q[R].cross(s[i].p1)>0)q[R]=s[i];
            }
            if(L<R)px[R-1]=q[R-1].line_intersection(q[R]);
        }
        while(L<R&&q[L].cross(px[R-1])<=0)--R;
        p.clear();
        if(R-L<=1)return 0;
        px[R]=q[R].line_intersection(q[L]);
        for(int i=L;i<=R;++i)p.push_back(px[i]);
        return R-L+1;
    }
};
const int maxn=105;
const double bw=10000;
polygon<double> poly;
vector<line<double> >s;
int n,v[maxn],u[maxn],w[maxn];
int main(){
    while(~scanf("%d",&n)&&n){
        for(int i=0;i<n;++i)scanf("%d%d%d",&v[i],&u[i],&w[i]);
        for(int i=0;i<n;++i){
            s.clear();
            bool ok=1;
            for(int j=0;j<n;++j)if(i!=j){
                if(v[i]<=v[j]&&u[i]<=u[j]&&w[i]<=w[j]){ok=0;break;}
                if(v[i]>=v[j]&&u[i]>=u[j]&&w[i]>=w[j])continue;
                double a=(bw/v[j]-bw/w[j])-(bw/v[i]-bw/w[i]);
                double b=(bw/u[j]-bw/w[j])-(bw/u[i]-bw/w[i]);
                double c=bw/w[j]-bw/w[i];
                point<double> t,x(b,-a);
                if(fabs(a)>fabs(b))t=point<double>(-c/a,0);
                else t=point<double>(0,-c/b);
                s.push_back(line<double>(t,t+x));
            }
            if(ok){
                s.push_back(line<double>(point<double>(0,0),point<double>(0,-1)));
                s.push_back(line<double>(point<double>(0,0),point<double>(1,0)));
                s.push_back(line<double>(point<double>(0,1),point<double>(-1,2)));
                if(!poly.halfplane_intersection(s))ok=0;
            }
            puts(ok?"Yes":"No");
        }
    }
    return 0;
}

2015年12月28日 星期一

[ UVA ] 1396 - Most Distant Point from the Sea

題目:
https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=4142

解法:
這題要算距離圖多邊形邊最遠的點,想法是半平面交+二分搜尋,每次把多邊形的每條邊向內移動m單位,之後判斷半平面交面積是否為0,搜尋m的邊界

code:
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
#include<bits/stdc++.h>
using namespace std;
template<typename T>
struct point{
    T x,y;
    point(){}
    point(const T&dx,const T&dy):x(dx),y(dy){}
    inline const point operator+(const point &b)const{
        return point(x+b.x,y+b.y);
    }
    inline const point operator-(const point &b)const{
        return point(x-b.x,y-b.y);
    }
    inline const point operator*(const T &b)const{
        return point(x*b,y*b);
    }
    inline const point operator/(const T &b)const{
        return point(x/b,y/b);
    }
    inline const T dot(const point &b)const{
        return x*b.x+y*b.y;
    }
    inline const T cross(const point &b)const{
        return x*b.y-y*b.x;
    }
    inline point normal()const{/*求法向量*/
        return point(-y,x);
    }
    inline const T abs2()const{/*向量長度的平方*/
        return dot(*this);
    }
};
template<typename T>
struct line{
    line(){}
    point<T> p1,p2;
    line(const point<T>&x,const point<T>&y):p1(x),p2(y){}
    inline bool parallel(const line &l)const{/*直線平行*/
        return (p1-p2).cross(l.p1-l.p2)==0;
    }
    inline T cross(const point<T> &p)const{/*點和有向直線的關係,>0左邊、=0在線上<0右邊*/
        return (p2-p1).cross(p-p1);
    }
    inline point<T> line_intersection(const line &l)const{/*直線交點*/
        point<T> a=p2-p1,b=l.p2-l.p1,s=l.p1-p1;
        return p1+a*s.cross(b)/a.cross(b);
    }
};
template<typename T>
struct polygon{
    polygon(){}
    std::vector<point<T> > p;
    inline const point<T>& operator[](int id)const{
        return p[id];
    }
    inline static char sign(const T&x){
        return x>=0?1:-1;
    }
    inline static bool angle_cmp(const line<T>& A,const line<T>& B){
        point<T>a=A.p2-A.p1,b=B.p2-B.p1;
        char ay=sign(a.y),by=sign(b.y),ax=sign(a.x),bx=sign(b.x);
        return ay>by||(ay==by&&(ax*ay>bx*by||(ax*ay==bx*by&&a.cross(b)>0)));
    }
    inline int halfplane_intersection(std::vector<line<T> > &s){
        sort(s.begin(),s.end(),angle_cmp);
        int L,R,n=s.size();
        std::vector<point<T> > px(n);
        std::vector<line<T> > q(n);
        q[L=R=0]=s[0];
        for(int i=1;i<n;++i){
            while(L<R&&s[i].cross(px[R-1])<=0)--R;
            while(L<R&&s[i].cross(px[L])<=0)++L;
            q[++R]=s[i];
            if(q[R].parallel(q[R-1])){
                --R;
                if(q[R].cross(s[i].p1)>0)q[R]=s[i];
            }
            if(L<R)px[R-1]=q[R-1].line_intersection(q[R]);
        }
        while(L<R&&q[L].cross(px[R-1])<=0)--R;
        p.clear();
        if(R-L<=1)return 0;
        px[R]=q[R].line_intersection(q[L]);
        for(int i=L;i<=R;++i)p.push_back(px[i]);
        return R-L+1;
    }
};
int n;
vector<line<double> > l;
point<double> p[200],v[200],v2[200];
polygon<double> poly;
int main(){
    while(scanf("%d",&n)&&n){
        for(int i=0;i<n;++i)
            scanf("%lf%lf",&p[i].x,&p[i].y);
        for(int i=0;i<n;++i){
            v[i]=p[(i+1)%n]-p[i];
            v2[i]=v[i].normal()/sqrt(v[i].abs2());
        }
        l.resize(n);
        double L=0,R=10000;//二分搜
        while(R-L>1e-8){
            double mid=L+(R-L)/2;
            for(int i=0;i<n;++i)
                l[i]=line<double>(p[i]+v2[i]*mid,p[i]+v2[i]*mid+v[i]);
            int m=poly.halfplane_intersection(l);
            if(!m)R=mid;
            else L=mid;
        }
        printf("%.6lf\n",L);
    }
    return 0;
}