题目描述
在古老的宝兰国有 N 座城市和 M 条双向道路。随着时间的流逝,一些道路渐渐变得破旧,最后因为损坏而无法使用,而从来没有人维修这些道路。作为古宝兰国历史的热爱者,你想要做一个小小的研究。为此,你想要写一个程序来处理以下的操作:
• D K,代表输入中的第 K 条道路损坏了。道路从 1 开始编号;
• P A B,代表编号为 A 的城市的人口数变为了 B。
我们称一些城市构成的集合为一个区域,当且仅当对于集合中的任意两座城市,都可以通过没有损坏的道路,仅经过集合中的城市互相到达。区域的人口数即为集合中所有城市的人口数之和。
给定初始的道路、人口数,以及 M 个操作。你的任务就是,在每次询问后输出人口数最大的区域中有多少个城市。
输入格式
输入数据的第一行包含三个整数 N、M 和 Q,分别代表城市数、道路数和操作数。接下来一行包含 N 个整数 P1, P2, . . . , PN,以空格隔开,代表每个城市的人口数。接下来 M 行,每行包含两个整数 Xj 和 Yj,代表编号为 Xj 和 Yj 之间有一条双向道路。接下来 Q 行,每行包含一个操作,格式如题目描述中所述。
输出格式
输出 Q 行,依次代表每次操作后人口数最多的区域的大小。
并查集。既然它是删边那我就反过来倒着加边。30分。(树状数组说好的logn复杂度?但求区间最值好像不止这点。。。
数列每次修改一个数值求最大值?看了大神代码果然用优先队列过的(然而并不理解为什么可以用while过滤。。。
然后注意一下以后在codechef上提交都用lld,不然会WA
#include<iostream> #include<algorithm> #include<string> #include<map>//ll dx[4]={0,0,-1,1};ll dy[4]={-1,1,0,0}; #include<set>// #include<vector> #include<cmath> #include<stack> #include<string.h> #include<stdlib.h> #include<cstdio> #define ll long long #define lowbit(x) (x) & (-x) using namespace std; map<char,int> r[27]; struct node{ int a,b,c; }x[500005]; struct node2{ char a; int b,c,d; }y[500005]; int fa[500005]; int n,m,q; int find(int v){ if (fa[v] == v) return v; else return fa[v]=find(fa[v]); } int g[500005]; int c2[500010],w[500005]; void update2(int ii,int val){ //修改点 w[ii]=val; for(int i=ii; i<=n+5; i+=lowbit(i)){ if(val>c2[i]) c2[i]=val; else break; } } int query(int l, int r){ int s=w[r];//上边界 while (l!=r){ for(r-=1;r-lowbit(r)>=l;r-=lowbit(r)){ s=max(s,c2[r]);//注意计算区间,不要夸区间 } s=max(s,w[r]); //下边界 } return s; } int main(){ scanf("%d%d%d",&n,&m,&q); for(int i=0;i<=n;++i){ fa[i]=i; } for(int i=1;i<=n;++i){ scanf("%d",&g[i]); update2(i,g[i]); } for(int i=1;i<=m;++i){ scanf("%d%d",&x[i].a,&x[i].b); x[i].c=0; } for(int i=0;i<q;++i){ getchar(); scanf("%c",&y[i].a); if(y[i].a=='D'){ scanf("%d",&y[i].b); x[y[i].b].c=1; } else{ scanf("%d%d",&y[i].b,&y[i].c); int tmp=y[i].c; y[i].c=g[y[i].b]; g[y[i].b]=tmp; update2(y[i].b,tmp); } } int maxx=0,ss=0; for(int i=1;i<=m;++i){ if(x[i].c==1){ maxx=max(w[x[i].a],maxx); maxx=max(w[x[i].b],maxx); continue; } int aa=find(x[i].a),bb=find(x[i].b); if(aa!=bb){ fa[aa]=bb; update2(bb,w[bb]+w[aa]); update2(aa,0); if(w[bb]>maxx){ maxx=w[bb]; } } } for(int i=q-1;i>=0;--i){ y[i].d=query(1,n); if(y[i].a=='D'){ int p=y[i].b; int aa=find(x[p].a),bb=find(x[p].b); if(aa!=bb){ fa[aa]=bb; update2(bb,w[bb]+w[aa]); update2(aa,0); } } else{ int p=y[i].b; int aa=find(p); update2(aa,w[aa]+y[i].c-g[p]); g[p]=y[i].c; } } for(int i=0;i<q;++i) printf("%d\n",y[i].d); }
【线段树版100分代码】
#include<iostream> #include<algorithm> #include<string> #include<map>//ll dx[4]={0,0,-1,1};ll dy[4]={-1,1,0,0}; #include<set>// #include<vector> #include<cmath> #include<stack> #include<string.h> #include<stdlib.h> #include<cstdio> #define ll long long #define MAXM 500005 #define lowbit(x) (x) & (-x) using namespace std; struct node{ int a,b,c; }x[500005]; struct node2{ char a; int b; ll c,d; }y[500005]; int fa[500005]; int n,m,q; int find(int v){ if (fa[v] == v) return v; else return fa[v]=find(fa[v]); } ll g[500005]; ll w[500005]; struct SegTree //求最值 { struct node { long long num, sum; }tree[MAXM << 2]; int L, R; long long V; void pushDown(int u, int l, int r, int m)//向下更新节点(节省时间) { if (tree[u].num != 0) { node &lson = tree[u << 1], &rson = tree[u << 1 | 1]; lson.num += tree[u].num; rson.num += tree[u].num; tree[u].sum += tree[u].num; tree[u].num = 0; } } void pushUp(int u) //【改】 { tree[u].sum = max(tree[u << 1].sum + tree[u << 1].num, tree[u << 1 | 1].sum + tree[u << 1 | 1].num); } void built(int u, int l, int r) { tree[u].num = 0; if (l == r) { tree[u].sum = 0; return; } int mid = l + r >> 1; built(u << 1, l, mid); built(u << 1 | 1, mid + 1, r); pushUp(u); } void _add(int u, int l, int r)//区间或者点加值 { int mid = l + r >> 1; if (L <= l&&r <= R) { tree[u].num += V; //【改,求和是V*(r-l+1)】 //【改=会错】 pushDown(u, l, r, mid); return; } pushDown(u, l, r, mid); if (L <= mid) _add(u << 1, l, mid); if (R>mid) _add(u << 1 | 1, mid + 1, r); pushUp(u); } long long _query(int u, int l, int r) { int mid = l + r >> 1; if (L <= l&&r <= R) { pushDown(u, l, r, mid); return tree[u].sum; } pushDown(u, l, r, mid); long long cnt = 0; if (L <= mid) cnt = max(cnt, _query(u << 1, l, mid)); //【改】 if (mid<R) cnt = max(cnt, _query(u << 1 | 1, mid + 1, r)); //【改】 pushUp(u); return cnt; } void add(int l, int r, long long v) { L = l; R = r; V = v; _add(1, 1, n); } long long query(int l, int r) { if (l <= r) { L = l, R = r; return _query(1, 1, n); } else return 0; } }A; int main(){ scanf("%d%d%d",&n,&m,&q); for(int i=0;i<=n;++i){ fa[i]=i; } for(int i=1;i<=n;++i){ scanf("%lld",&g[i]); //每个城市的人口数 w[i]=g[i]; A.add(i,i,g[i]); } for(int i=1;i<=m;++i){ scanf("%d%d",&x[i].a,&x[i].b); //编号之间有一条双向道路 } for(int i=0;i<q;++i){ getchar(); scanf("%c",&y[i].a); if(y[i].a=='D'){ scanf("%d",&y[i].b); //第 K 条道路损坏了 x[y[i].b].c=1; } else{ scanf("%d%lld",&y[i].b,&y[i].c); //编号为 A 的城市的人口数变为了 B ll tmp=y[i].c; A.add(y[i].b,y[i].b,tmp-g[y[i].b]); y[i].c=g[y[i].b]; g[y[i].b]=tmp; w[y[i].b]=tmp; } } for(int i=1;i<=m;++i){ if(x[i].c==1) continue; int aa=find(x[i].a),bb=find(x[i].b); if(aa!=bb){ fa[aa]=bb; A.add(bb,bb,w[aa]); A.add(aa,aa,-w[aa]); w[bb]+=w[aa]; w[aa]=0; } } for(int i=q-1;i>=0;--i){ y[i].d=A.query(1,n); if(y[i].a=='D'){ int p=y[i].b; int aa=find(x[p].a),bb=find(x[p].b); if(aa!=bb){ fa[aa]=bb; A.add(bb,bb,w[aa]); A.add(aa,aa,-w[aa]); w[bb]+=w[aa]; w[aa]=0; } } else{ int p=y[i].b; int aa=find(p); A.add(aa,aa,y[i].c-g[p]); w[aa]+=y[i].c-g[p]; g[p]=y[i].c; } } for(int i=0;i<q;++i) printf("%lld\n",y[i].d); return 0; }
用set的方法:
每次要合并就先把set里面的a和b先删掉(用pair存,默认以first优先排序),再ab合并后把新的根节点和值重新存进去。
更改点:先把set里面的这个点删掉(搜根节点),重新计算点值后存入
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int N = 5e5 + 5; int type,q,u,v,m; ll val[N]; pair < int ,int > edges[N]; int uf[N]; ll prev[N]; int good[N]; int a[N]; int b[N]; ll ans[N]; string cur[N]; set < pair < ll , int > , greater < pair < ll , int > > > DSU; ll QUERY(){ set < pair < ll , int > > :: iterator it = DSU.begin(); return it->first; } int FIND(int u) { if(uf[u]!=uf[uf[u]]){ uf[u] = FIND(uf[u]); } return uf[u]; } void UNION(int u , int v) { int xx = FIND(u); int yy = FIND(v); if(xx==yy) return; DSU.erase(make_pair(val[xx],xx)); DSU.erase(make_pair(val[yy],yy)); uf[yy] = xx; val[xx] += val[yy]; DSU.insert(make_pair(val[xx],xx)); } int main() { ios_base::sync_with_stdio(false); cin.tie(NULL); int t,n; cin >> n >> m >> q; for(int i = 1; i<=n; ++i){ cin >> val[i]; uf[i] = i; } for(int i = 1; i<=m; ++i){ cin >> u >> v; edges[i] = make_pair(u,v); good[i] = true; } for(int i = 1; i<=q; ++i){ cin >> cur[i]; if(cur[i][0]=='D'){ cin >> a[i]; good[a[i]] = false; } else{ cin >> a[i] >> b[i]; prev[i] = val[a[i]]; val[a[i]] = b[i]; } } for(int i = 1; i<=n; ++i){ DSU.insert(make_pair(1LL * val[i],i)); } for(int i = 1; i<=m; ++i){ if(good[i]){ UNION(edges[i].first,edges[i].second); } } ans[q] = QUERY(); for(int i = q; i > 0; --i){ if(cur[i][0]=='D'){ UNION(edges[a[i]].first,edges[a[i]].second); } else{ int ind = a[i]; int newval = b[i]; int leader = FIND(ind); DSU.erase(make_pair(val[leader],leader)); val[leader] -= newval; val[leader] += prev[i]; DSU.insert(make_pair(val[leader],leader)); } ans[i-1] = QUERY(); } for(int i = 1; i<=q; ++i){ cout << ans[i] << endl; } return 0; }