Cdq分治整体二分学习记录

这点东西前前后后拖了好几个星期才学会……还是自己太菜啊。

Cdq分治的思想是:把问题序列分割成左右两个,先单独处理左边,再处理左边对右边的影响,再单独处理右边。这样可以消去数据结构上的一个log,降低编码复杂度。

整体二分:当一个询问的答案满足二分性质时,我们可以按照答案的大小分割整个查询和修改序列。每次把序列分成互不相同的两部分。这样能把数据结构的二分拿出来,降低编码复杂度。

说白了,就是当你懒得写树套树或者惨遭卡内存时候的骗分办法。

好了,上例题吧:

BZOJ2683:

二维单点加,矩形查。可以kdtree或树套树水过。

然而这里要用cdq分治。我们把一个查询利用二维前缀和原理拆成4个,然后按x排序,对t(时间)cdq分治,用树状数组维护y上的前缀和。我们先处理t在左边对右边查询的影响,然后再递归处理左右。

代码:

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 #define debug cout
 6 using namespace std;
 7 const int maxn=8e5+1e2;
 8 
 9 int n;
10 
11 struct BinaryIndexTree {
12     int dat[maxn];
13     #define lowbit(x) (x&-x)
14     inline void update(int pos,int x) {
15         while( pos < maxn ) {
16             dat[pos] += x ,
17             pos += lowbit(pos);
18         }
19     }
20     inline int query(int pos) {
21         int ret = 0;
22         while( pos )
23             ret += dat[pos] ,
24             pos -= lowbit(pos);
25         return ret;
26     }
27 }bit;
28 
29 struct QNode {
30     int tpe,x,y,aid,tme,lam;
31     friend bool operator < (const QNode &a,const QNode &b) {
32         if( a.x != b.x )
33             return a.x < b.x;
34         if( a.y != b.y )
35             return a.y < b.y;
36         return a.tpe < b.tpe;
37     }
38 }ns[maxn],tp[maxn];
39 
40 int cnt,acn;
41 int ans[maxn];
42 
43 inline void cdq(int l,int r) {
44     if( l == r )
45         return;
46     const int mid = ( l + r ) >> 1;
47     for(int i=l;i<=r;i++) {
48         if( ns[i].tme <= mid && ns[i].tpe == 1 )
49             bit.update(ns[i].y,ns[i].lam);
50         if( ns[i].tme > mid && ns[i].tpe == 2 )
51             ans[ns[i].aid] += ns[i].lam * bit.query(ns[i].y);
52     }
53     for(int i=l;i<=r;i++)
54         if( ns[i].tme <= mid && ns[i].tpe == 1 )
55             bit.update(ns[i].y,-ns[i].lam);
56     int l1 = l , l2 = mid + 1;
57     for(int i=l;i<=r;i++)
58         if( ns[i].tme <= mid )
59             tp[l1++] = ns[i];
60         else
61             tp[l2++] = ns[i];
62     for(int i=l;i<=r;i++)
63         ns[i] = tp[i];
64     cdq(l,mid);
65     cdq(mid+1,r);
66 }
67 
68 int main() {
69     static int t,x,y,xx,yy,lam;
70     scanf("%d",&n);
71     while( scanf("%d",&t) == 1 && t != 3 ) {
72         if( t == 1 ) {
73             scanf("%d%d%d",&x,&y,&lam);
74             ns[++cnt].tpe = t , ns[cnt].x = x , ns[cnt].y = y ,
75             ns[cnt].lam = lam , ns[cnt].tme = cnt;
76         }
77         else {
78             scanf("%d%d%d%d",&x,&y,&xx,&yy);
79             --x , --y , ++acn;
80             ns[++cnt].tpe = t , ns[cnt].x = x , ns[cnt].y = y ,
81             ns[cnt].aid = acn , ns[cnt].tme = cnt , ns[cnt].lam = 1;
82             ns[++cnt].tpe = t , ns[cnt].x = xx , ns[cnt].y = yy ,
83             ns[cnt].aid = acn , ns[cnt].tme = cnt , ns[cnt].lam = 1;
84             ns[++cnt].tpe = t , ns[cnt].x = x , ns[cnt].y = yy ,
85             ns[cnt].aid = acn , ns[cnt].tme = cnt , ns[cnt].lam = -1;
86             ns[++cnt].tpe = t , ns[cnt].x = xx , ns[cnt].y = y ,
87             ns[cnt].aid = acn , ns[cnt].tme = cnt , ns[cnt].lam = -1;
88         }
89     }
90     sort(ns+1,ns+1+cnt);
91     cdq(1,cnt);
92     
93     for(int i=1;i<=acn;i++)
94         printf("%d\n",ans[i]);
95     
96     return 0;
97 }
View Code

 

BZOJ3110:

本来是一道树套树卡内存神题……

这题我们可以整体二分,对整个序列维护一个支持区间加,区间求和的树状数组(什么你不会?线段树也行),然后对于每个询问,如果>mid的区间和比查询的k小,则把询问分到左边,同时让k减去>mid的权值数量的区间和。反之直接分配到右边。

代码:

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<algorithm>
  5 #define lli long long int
  6 #define debug cout
  7 using namespace std;
  8 const int maxn=5e4+1e2;
  9  
 10 struct BinaryIndexTree {
 11     lli org[maxn],del[maxn];
 12     int siz;
 13     #define lowbit(x) (x&-x)
 14      
 15     inline void cupd(lli* dst,int pos,int add) {
 16         while( pos <= siz )
 17             dst[pos] += add , pos += lowbit(pos);
 18     }
 19     inline lli cqry(lli* sou,int pos) {
 20         lli ret = 0;
 21         while( pos )
 22             ret += sou[pos] , pos -= lowbit(pos);
 23         return ret;
 24     }
 25     inline lli qryp(int pos) {
 26         return cqry(org,pos) + cqry(del,pos) * pos;
 27     }
 28     inline void update(int l,int r,int add) {
 29         cupd(org,l,-(l-1)*add);
 30         cupd(org,r,r*add);
 31         cupd(del,l,add);
 32         cupd(del,r,-add);
 33     }
 34     inline lli query(int l,int r) {
 35         return qryp(r) - qryp(l-1);
 36     }
 37     inline void resize(int ss) {
 38         siz = ss;
 39     }
 40 }bit;
 41  
 42 int ans[maxn];
 43  
 44 struct QNode { // type == 1 means update , type == 2 means query;
 45     int tpe,l,r,x,qid;
 46     lli k;
 47 }ns[maxn],tpl[maxn],tpr[maxn];
 48  
 49 inline void solve(int ql,int qr,int al,int ar) {
 50     if( al == ar ) {
 51         for(int i=ql;i<=qr;i++)
 52             if( ns[i].tpe == 2 ) {
 53                 ans[ns[i].qid] = al;
 54             }
 55         return;
 56     }
 57     const int amid = ( al + ar ) >> 1;
 58     int cntl = 0 , cntr = 0;
 59     for(int i=ql;i<=qr;i++) {
 60         if( ns[i].tpe == 1 ) {
 61             if( ns[i].x <= amid ) {
 62                 tpl[++cntl] = ns[i];
 63             } else {
 64                 bit.update(ns[i].l,ns[i].r,1);
 65                 tpr[++cntr] = ns[i];
 66             }
 67         }
 68         else {
 69             lli lam = bit.query(ns[i].l,ns[i].r);
 70             if( ns[i].k <= lam ) {
 71                 tpr[++cntr] = ns[i];
 72             } else {
 73                 ns[i].k -= lam;
 74                 tpl[++cntl] = ns[i];
 75             }
 76         }
 77     }
 78     for(int i=1;i<=cntr;i++)
 79         if( tpr[i].tpe == 1 )
 80             bit.update(tpr[i].l,tpr[i].r,-1);
 81      
 82     const int qmid = ql + cntl - 1;
 83     int c1 = ql , c2 = qmid + 1;
 84     for(int i=1;i<=cntl;i++)
 85         ns[c1++] = tpl[i];
 86     for(int i=1;i<=cntr;i++)
 87         ns[c2++] = tpr[i];
 88      
 89     solve(ql,qmid,al,amid);
 90     solve(qmid+1,qr,amid+1,ar);
 91 }
 92  
 93 inline int getint() {
 94     int ret = 0 , ch ;
 95     while( !isdigit(ch=getchar()) );
 96     do ret=ret*10+ch-'0'; while( isdigit(ch=getchar()) );
 97     return ret;
 98 }
 99 signed main() {
100     static int n,m,qid;
101     n = getint() , m = getint();
102     bit.resize(n);
103     for(int i=1;i<=m;i++) {
104         ns[i].tpe = getint() , ns[i].l = getint() , ns[i].r = getint();
105         if( ns[i].tpe == 1 ) {
106             scanf("%d",&ns[i].x);
107         } else {
108             scanf("%lld",&ns[i].k);
109             ns[i].qid = ++qid;
110         }
111     }
112      
113     solve(1,m,-n,n);
114      
115     for(int i=1;i<=qid;i++)
116         printf("%d\n",ans[i]);
117      
118     return 0;
119 }
View Code

 

BZOJ1901:

单点修改,查第k小的值。我们只需要把修改变成一个删除原权值的操作和一个插入新权值的操作,然后维护一个单点修改区间求和的树状数组就可以了。注意zoj上这题的双精题卡内存。

代码:

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<algorithm>
  5 #include<cctype>
  6 #define debug cout
  7 using namespace std;
  8 const int maxn=3e4+1e2;
  9  
 10 struct BinaryIndexTree {
 11     int dat[maxn],siz;
 12      
 13     #define lowbit(x) (x&-x)
 14      
 15     inline void update(int pos,int x) {
 16         while( pos <= siz )
 17             dat[pos] += x , pos += lowbit(pos);
 18     }
 19     inline int query(int pos) {
 20         int ret = 0;
 21         while( pos )
 22             ret += dat[pos] , pos -= lowbit(pos);
 23         return ret;
 24     }
 25     inline void resize(int ss) {
 26         siz = ss;
 27     }
 28 }bit;
 29  
 30 struct QNode {
 31     int tpe; // tpe == 1 means query , 0 means change
 32     int pos,val,del;
 33     int st,ed,k,qid;
 34 }ns[maxn],tp[2][maxn];
 35  
 36 int in[maxn],srt[maxn],ans[maxn],len;
 37  
 38 inline void solve(int ql,int qr,int al,int ar) {
 39     if( al == ar ) {
 40         for(int i=ql;i<=qr;i++)
 41             if( ns[i].tpe )
 42                 ans[ns[i].qid] = al;
 43         return;
 44     }
 45     const int amid = ( al + ar ) >> 1;
 46     int cntl = 0 , cntr = 0;
 47     for(int i=ql;i<=qr;i++) {
 48         if( ns[i].tpe ) {
 49             const int kk = bit.query(ns[i].ed) - bit.query(ns[i].st-1);
 50             if( ns[i].k > kk ) {
 51                 ns[i].k -= kk ,
 52                 tp[1][++cntr] = ns[i];
 53             } else tp[0][++cntl] = ns[i];
 54         } else {
 55             if( ns[i].val <= amid ) {
 56                 bit.update(ns[i].pos,ns[i].del);
 57                 tp[0][++cntl] = ns[i];
 58             } else tp[1][++cntr] = ns[i];
 59         }
 60     }
 61     for(int i=ql;i<=qr;i++)
 62         if( !ns[i].tpe && ns[i].val <= amid )
 63             bit.update(ns[i].pos,-ns[i].del);
 64     const int qmid = ql + cntl - 1;
 65     memcpy(ns+ql,tp[0]+1,sizeof(tp[0][0])*cntl);
 66     memcpy(ns+qmid+1,tp[1]+1,sizeof(tp[1][0])*cntr);
 67     solve(ql,qmid,al,amid);
 68     solve(qmid+1,qr,amid+1,ar);
 69 }
 70  
 71 inline int getint() {
 72     int ret = 0 , ch;
 73     while( !isdigit(ch=getchar()) );
 74     do ret=ret*10+ch-'0'; while( isdigit(ch=getchar()) );
 75     return ret;
 76 }
 77  
 78 int main() {
 79     static int n,m,cnt,qcnt;
 80     static char com[10];
 81     n = getint() , m = getint();
 82     for(int i=1;i<=n;i++) {
 83         ns[++cnt].val = in[i] = srt[++len] = getint() ,
 84         ns[cnt].pos = i;ns[cnt].del = 1;
 85     }
 86     for(int i=1,p;i<=m;i++) {
 87         scanf("%s",com);
 88         if( *com == 'Q' ) {
 89             ns[++cnt].tpe = 1 , ns[cnt].qid = ++qcnt;
 90             ns[cnt].st = getint() , ns[cnt].ed = getint() , ns[cnt].k = getint();
 91         } else {
 92             p = getint();
 93             ns[++cnt].pos = p , ns[cnt].val = in[p] , ns[cnt].del = -1;
 94             ns[++cnt].pos = p , srt[++len] = ns[cnt].val = in[p] = getint() , ns[cnt].del = 1;
 95         }
 96     }
 97     sort(srt+1,srt+1+len) , len = unique(srt+1,srt+1+len) - srt - 1;
 98     for(int i=1;i<=cnt;i++)
 99         if( !ns[i].tpe ) {
100             ns[i].val = lower_bound(srt+1,srt+1+len,ns[i].val) - srt;
101         }
102      
103     bit.resize(n);
104     solve(1,cnt,1,len);
105      
106     for(int i=1;i<=qcnt;i++)
107         printf("%d\n",srt[ans[i]]);
108      
109     return 0;
110 }
View Code

 

BZOJ1146:

这题可以权值线段树套树链剖分的线段树,也可以带修主席树。总之就是卡内存+不是人写的……

所以我们要整体二分,同上一题,只不过变到了树上。所以我们需要树链剖分线段树。

代码:

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<algorithm>
  5 #include<cctype>
  6 #define debug cerr
  7 using namespace std;
  8 const int maxn=8e4+1e2;
  9  
 10 struct QNode {
 11     int tpe; // 1 means query , 0 means change
 12     int k,a,b,qid;
 13     int pos,val,add;
 14 }ns[maxn<<2],tp[2][maxn<<2];
 15  
 16 int in[maxn],srt[maxn<<1],ans[maxn],len;
 17 int s[maxn],t[maxn<<1],nxt[maxn<<1];
 18 int fa[maxn],dep[maxn],siz[maxn],son[maxn],top[maxn],num[maxn],cov[maxn];
 19 int l[maxn<<3],r[maxn<<3],lson[maxn<<3],rson[maxn<<3],su[maxn<<3],cnt;
 20 int n,m;
 21  
 22 inline void build(int pos,int ll,int rr) {
 23     l[pos] = ll , r[pos] = rr;
 24     if( ll == rr ) return;
 25     const int mid = ( ll + rr ) >> 1;
 26     build(lson[pos]=++cnt,ll,mid);
 27     build(rson[pos]=++cnt,mid+1,rr);
 28 }
 29 inline void update(int pos,int tar,int x) {
 30     if( tar < l[pos] || r[pos] < tar ) return;
 31     if( l[pos] == r[pos] && l[pos] == tar ) {
 32         su[pos] += x;
 33         return;
 34     }
 35     update(lson[pos],tar,x);
 36     update(rson[pos],tar,x);
 37     su[pos] = su[lson[pos]] + su[rson[pos]];
 38 }
 39 inline int query(int pos,int ll,int rr) {
 40     if( rr < l[pos] || r[pos] < ll ) return 0;
 41     if( ll <= l[pos] && r[pos] <= rr ) return su[pos];
 42     return query(lson[pos],ll,rr) + query(rson[pos],ll,rr);
 43 }
 44  
 45 inline void addedge(int from,int to) {
 46     static int cnt = 0;
 47     t[++cnt] = to , nxt[cnt] = s[from] , s[from] = cnt;
 48 }
 49 inline void pre(int pos) {
 50     siz[pos] = 1;
 51     for(int at=s[pos];at;at=nxt[at])
 52         if( t[at] != fa[pos] ) {
 53             fa[t[at]] = pos , dep[t[at]] = dep[pos] + 1;
 54             pre(t[at]);
 55             siz[pos] += siz[t[at]];
 56             son[pos] = siz[t[at]] > siz[son[pos]] ? t[at] : son[pos];
 57         }
 58 }
 59 inline void dfs(int pos) {
 60     top[pos] = pos == son[fa[pos]] ? top[fa[pos]] : pos;
 61     num[pos] = pos == son[fa[pos]] ? num[fa[pos]] + 1 : 1;
 62     for(int at=s[pos];at;at=nxt[at])
 63         if( t[at] != fa[pos] )
 64             dfs(t[at]);
 65     if( !son[pos] )
 66         build(cov[top[pos]]=++cnt,num[top[pos]],num[pos]);
 67 }
 68 inline int chain(int a,int b) {
 69     int ret = 0;
 70     while( top[a] != top[b] ) {
 71         if( dep[top[a]] > dep[top[b]] ) {
 72             ret += query(cov[top[a]],num[top[a]],num[a]),
 73             a = fa[top[a]];
 74         } else {
 75             ret += query(cov[top[b]],num[top[b]],num[b]),
 76             b = fa[top[b]];
 77         }
 78     }
 79     ret += query(cov[top[a]],min(num[a],num[b]),max(num[a],num[b]));
 80     return ret;
 81 }
 82  
 83 inline void solve(int ql,int qr,int al,int ar) {
 84     if( al == ar ) {
 85         for(int i=ql;i<=qr;i++)
 86             if( ns[i].tpe )
 87                 ans[ns[i].qid] = al;
 88         return;
 89     }
 90     const int amid = ( al + ar ) >> 1;
 91     int cntl = 0 , cntr = 0;
 92     for(int i=ql;i<=qr;i++) {
 93         if( ns[i].tpe ) {
 94             int kk = chain(ns[i].a,ns[i].b);
 95             if( ns[i].k > kk ) {
 96                 ns[i].k -= kk , tp[0][++cntl] = ns[i];
 97             } else tp[1][++cntr] = ns[i];
 98         } else {
 99             if( ns[i].val > amid ) {
100                 const int &pos = ns[i].pos;
101                 update(cov[top[pos]],num[pos],ns[i].add);
102                 tp[1][++cntr] = ns[i];
103             } else tp[0][++cntl] = ns[i];
104         }
105     }
106     for(int i=qr;i>=ql;i--)
107         if( ns[i].val > amid ) {
108             const int &pos = ns[i].pos;
109             update(cov[top[pos]],num[pos],-ns[i].add);
110         }
111     const int qmid = ql + cntl - 1;
112      
113     memcpy( ns + ql , tp[0] + 1 , sizeof(tp[0][0]) * cntl );
114     memcpy( ns + qmid + 1 , tp[1] + 1 , sizeof(tp[1][1]) * cntr );
115      
116     solve(ql,qmid,al,amid);
117     solve(qmid+1,qr,amid+1,ar);
118 }
119  
120 inline int getint() {
121     int ret = 0 , ch;
122     while( !isdigit(ch=getchar()) );
123     do ret=ret*10+ch-'0'; while( isdigit(ch=getchar()) );
124     return ret;
125 }
126 int main() {
127     static int qcnt,qlen;
128     n = getint() , m = getint();
129     qlen = n;
130     for(int i=1;i<=n;i++)
131         ns[i].pos = i , in[i] = ns[i].val = srt[++len] = getint() , ns[i].add = 1;
132     for(int i=1,a,b;i<n;i++) {
133         a = getint() , b = getint();
134         addedge(a,b) , addedge(b,a);
135     }
136     for(int i=1,k,p;i<=m;i++) {
137         k = getint();
138         if( !k ) {
139             p = getint();
140             ++qlen , ns[qlen].pos = p , ns[qlen].val = in[p] , ns[qlen].add = -1;
141             ++qlen , ns[qlen].pos = p , in[p] = ns[qlen].val = srt[++len] = getint() , ns[qlen].add = 1;
142         } else {
143             ++qlen , ns[qlen].tpe = 1 , ns[qlen].a = getint() , ns[qlen].b = getint() , ns[qlen].k = k , ns[qlen].qid = ++qcnt;
144         }
145     }
146      
147     sort(srt+1,srt+1+len);
148     len = unique(srt+1,srt+1+len) - srt - 1;
149     for(int i=1;i<=qlen;i++)
150         if( ! ns[i].tpe ) ns[i].val = lower_bound(srt+1,srt+1+len,ns[i].val) - srt;
151      
152     pre(1);dfs(1);
153     solve(1,qlen,0,len);
154      
155     for(int i=1;i<=qcnt;i++)
156         if( ans[i] ) printf("%d\n",srt[ans[i]]);
157         else puts("invalid request!");
158      
159     return 0;
160 }
View Code

 

BZOJ3237:

删除一组边问你是否联通。我们可以cdq分治求解。

维护每条边被删除的次数,递归左右时,如果这条边在某一侧被删除次数为0了则合并两边点所在的并查集。这里不要路径压缩,我们需要按秩合并。我们可以记录一个栈来回滚操作(当然你非得用主席树可持久化那也行)。查询时就看一下点1所在的联通块大小是否为n即可。是不是很好写啊?

代码:

 1 #include<cstdio>
 2 using namespace std;
 3 const int maxn=1e5+1e2,maxm=2e5+1e2,maxk=1e5+1e2;
 4  
 5 int fa[maxn],siz[maxn];
 6 int a[maxm],b[maxm];
 7 int len[maxk],met[maxk][6];
 8 int cnt[maxm],stk[maxn],top;
 9 char ans[maxk];
10 int n;
11  
12 inline int findfa(int x) {
13     return fa[x] == x ? x : findfa(fa[x]);
14 }
15  
16 inline void merge(int l,int r) {
17     for(int i=l;i<=r;i++)
18         for(int j=1;j<=len[i];j++) {
19             const int k = met[i][j];
20             if( --cnt[k] ) continue;
21             int aa = findfa(a[k]) , bb = findfa(b[k]);
22             if( aa == bb ) continue;
23             if( siz[aa] > siz[bb] ) fa[bb] = aa , siz[aa] += siz[bb] , stk[++top] = bb;
24             else fa[aa] = bb , siz[bb] += siz[aa] , stk[++top] = aa;
25         }
26 }
27 inline void resetcnt(int l,int r) {
28     for(int i=l;i<=r;i++)
29         for(int j=1;j<=len[i];j++)
30             ++cnt[met[i][j]];
31 }
32 inline void resetfa(int tar) {
33     while( top > tar ) {
34         const int pos = stk[top--];
35         siz[fa[pos]] -= siz[pos] , fa[pos] = pos;
36     }
37 }
38  
39 inline void solve(int ll,int rr) {
40     if( ll == rr ) {
41         ans[ll] = ( siz[findfa(1)] == n );
42         return;
43     }
44     const int mid = ( ll + rr ) >> 1 , mem = top;
45      
46     merge(ll,mid);
47     solve(mid+1,rr);
48     resetfa(mem);
49     resetcnt(ll,mid);
50      
51     merge(mid+1,rr);
52     solve(ll,mid);
53     resetfa(mem);
54     resetcnt(mid+1,rr);
55 }
56  
57 inline void init() {
58     for(int i=1;i<=n;i++)
59         fa[i] = i , siz[i] = 1;
60 }
61  
62 int main() {
63     static int m,k;
64     scanf("%d%d",&n,&m);
65     for(int i=1;i<=m;i++)
66         scanf("%d%d",a+i,b+i);
67     scanf("%d",&k);
68     for(int i=1;i<=k;i++) {
69         scanf("%d",len+i);
70         for(int j=1;j<=len[i];j++)
71             scanf("%d",met[i]+j);
72     }
73      
74     init();
75     resetcnt(1,k);
76     for(int i=1;i<=m;i++)
77         if( !cnt[i] ) {
78             int aa = findfa(a[i]) , bb = findfa(b[i]);
79             if( aa == bb ) continue;
80             if( siz[aa] > siz[bb] ) fa[bb] = aa , siz[aa] += siz[bb];
81             else fa[aa] = bb , siz[bb] += siz[aa];
82         }
83      
84     solve(1,k);
85      
86     for(int i=1;i<=k;i++)
87         puts( ans[i] ? "Connected" : "Disconnected" );
88      
89     return 0;
90 }
View Code

 

BZOJ2001:

动态维护最小生成树。

我们可以LCT,可做但据说并不能AC(常数巨大)。

所以我们需要cdq分治。对于每层,我们删除无用边,缩点必需边,可以把边数化成O(n)级别的,然后再向下递归即可。底层直接更新权值,计算最小生成树,记录答案。

实现的时候,我们记录每一条边实际权值,和它原来的编号和在当前边序列中的编号的映射关系即可。每层并查集初始化的时候仅初始化在这层存在的边。

代码:

  1 #include<cstdio>
  2 #include<cstring>
  3 #include<algorithm>
  4 #include<cctype>
  5 #define lli long long int
  6 using namespace std;
  7 const int maxn=2e4+1e2,maxm=5e4+1e2,maxd=25;
  8 const int inf=0x3f3f3f3f;
  9  
 10 struct Edge {
 11     int a,b,val,id;
 12     friend bool operator < (const Edge &a,const Edge &b) {
 13         return a.val < b.val;
 14     }
 15 }ess[maxd][maxm],now[maxm],etp[maxm];
 16 int opeid[maxm],opeval[maxm];
 17 int wei[maxm],cov[maxm]; // weight of edge , convert real id to operated id.
 18 int fa[maxn];
 19 lli ans[maxm];
 20  
 21 inline int findfa(int x) {
 22     return fa[x] == x ? x : fa[x] = findfa(fa[x]);
 23 }
 24 inline void merge(int x,int y) {
 25     x = findfa(x) , y = findfa(y);
 26     if( x == y ) return;
 27     fa[x] = y;
 28 }
 29 inline void reset(Edge* es,int len) {
 30     for(int i=1;i<=len;i++)
 31         fa[es[i].a] = es[i].a ,
 32         fa[es[i].b] = es[i].b;
 33 }
 34  
 35 inline lli contraction(Edge* es,int &len) {
 36     lli ret = 0;
 37     int tpl = 0;
 38      
 39     reset(es,len);
 40     sort(es+1,es+1+len);
 41     for(int i=1;i<=len;i++)
 42         if( findfa(es[i].a) != findfa(es[i].b) ) { // find a mst 
 43             etp[++tpl] = es[i] , merge(es[i].a,es[i].b);
 44         }
 45      
 46     reset(etp,tpl);
 47     for(int i=1;i<=tpl;i++)
 48         if( etp[i].val != -inf ) {
 49             ret += etp[i].val , merge(etp[i].a,etp[i].b);
 50         }
 51      
 52     tpl = 0;
 53     for(int i=1;i<=len;i++)
 54         if( findfa(es[i].a) != findfa(es[i].b) ) {
 55             etp[++tpl] = es[i];
 56             etp[tpl].a = findfa(es[i].a) , etp[tpl].b = findfa(es[i].b) ,
 57             cov[es[i].id] = tpl;
 58         }
 59      
 60     reset(es,len);
 61     len = tpl;
 62     memcpy(es+1,etp+1,sizeof(es[0])*len);
 63      
 64     return ret;
 65 }
 66 inline void reduction(Edge* es,int &len) {
 67     int tpl = 0;
 68      
 69     reset(es,len);
 70     sort(es+1,es+1+len);
 71     for(int i=1;i<=len;i++)
 72         if( findfa(es[i].a) != findfa(es[i].b) ) {
 73             merge(es[i].a,es[i].b);
 74             etp[++tpl] = es[i];
 75             cov[es[i].id] = tpl;
 76         }
 77         else if( es[i].val == inf ) {
 78             etp[++tpl] = es[i];
 79             cov[es[i].id] = tpl;
 80         }
 81      
 82     reset(es,len) , len = tpl;
 83     memcpy(es+1,etp+1,sizeof(es[0])*len);
 84 }
 85 inline lli mst(Edge* es,int len) {
 86     lli ret = 0;
 87     reset(es,len);
 88     sort(es+1,es+1+len);
 89     for(int i=1;i<=len;i++)
 90         if( findfa(es[i].a) != findfa(es[i].b) )
 91             ret += es[i].val , merge(es[i].a,es[i].b);
 92     return ret;
 93 }
 94  
 95 inline void solve(Edge* es,int dep,int len,int ll,int rr,lli res) {
 96     if( ll == rr )
 97         wei[opeid[ll]] = opeval[ll];
 98     for(int i=1;i<=len;i++) {
 99         es[i].val = wei[es[i].id];
100         now[i] = es[i] , cov[now[i].id] = i;
101     }
102     if( ll == rr ) {
103         ans[ll] = res + mst(now,len);
104         return;
105     }
106      
107      
108     for(int i=ll;i<=rr;i++) {
109         now[cov[opeid[i]]].val = -inf;
110     }
111     res += contraction(now,len);
112      
113      
114     for(int i=ll;i<=rr;i++)
115         now[cov[opeid[i]]].val = inf;
116     reduction(now,len);
117      
118     memcpy(ess[dep+1]+1,now+1,sizeof(now[0])*len);
119      
120     const int mid = ( ll + rr ) >> 1;
121     solve(ess[dep+1],dep+1,len,ll,mid,res);
122     solve(ess[dep+1],dep+1,len,mid+1,rr,res);
123 }
124  
125 inline char nextchar() {
126     static char buf[1<<22],*st=buf+(1<<22),*ed=buf+(1<<22);
127     if( st == ed ) ed = buf + fread(st=buf,1,1<<22,stdin);
128     return st != ed ? *st++ : -1;
129 }
130 inline int getint() {
131     int ret = 0,ch;
132     while( !isdigit(ch=nextchar()) );
133     do ret=ret*10+ch-'0'; while( isdigit(ch=nextchar()) );
134     return ret;
135 }
136 int main() {
137     static int n,m,q;
138     scanf("%d%d%d",&n,&m,&q);
139     for(int i=1,a,b,l;i<=m;i++) {
140         scanf("%d%d%d",&a,&b,&l);
141         ess[0][i] = (Edge){a,b,l,i};
142         wei[i] = l;
143     }
144     for(int i=1;i<=q;i++)
145         scanf("%d%d",opeid+i,opeval+i);
146      
147     solve(ess[0],0,m,1,q,0);
148      
149     for(int i=1;i<=q;i++)
150         printf("%lld\n",ans[i]);
151      
152     return 0;
153 }
View Code

 

为什么代码都写得这么长这么丑还常数那么大?……果然还是自己太菜啊。

posted @ 2018-01-21 16:41  Cmd2001  阅读(287)  评论(0编辑  收藏  举报