【NOIP2017提高组模拟6.27】C
2017-06-27 22:09
387 查看
Description
蜘蛛精大爷是世界上最爷的爷,ta的图论专著《蜘蛛精大爷教你学做人OI之图论》正在热卖,只要233美元一本,每人限购一本。。。。。。在某弱的不懈要求下,ta给某弱出了一道题,然而某弱太弱了,只好向你求助。给你一张n个结点,m条边的无向图,每个结点都有一个整数权值。你需要执行一系列操作。操作分为三种,如下表所示。
操作
备注
D x (1<=x<=m)
删除编号为x的边。输入保证每条边至多被删除一次。
Q x k (1<=x<=n)
计算出结点x所在的联通块中,第k大的权值。如果不存在,输出0。
C x v (1<=x<=n)
把结点x的权值改为v。
操作序列的结束标志为单个字母E。结点编号为1到n,边的编号为1到m。
Input
输入第一行为两个整数n和m。接下来n行每行一个整数,表示个节点的初始权值。
接下来m行每行两个整数,表示一条边的两个端点。
接下来是各条指令,以单个字母E结尾。
Output
对于每个Q指令,输出一行,包括一个计算结果。Sample Input
3 310
20
30
1 2
2 3
1 3
D 3
Q 1 2
Q 2 1
D 2
Q 3 2
C 1 50
Q 1 1
E
Sample Output
2030
0
50
Data Constraint
对于前50%的数据,n <= 1000,m <= 5000。对于前10%的数据,没有D指令且没有C指令。
对于另20%的数据,没有D指令。
对于另20%的数据,没有C指令。
对于100%的数据,1 <= n <= 20000,0 <= m <= 60000,每个结点的权值为绝对值不超过
的整数,Q指令和C指令不超过200000条。
Solution
这题的数据范围没有完全给定,这就使得容易RE首先把所有点的权值都看成正的,就是加上一个比较大的常数,输出时减掉即可
存有多少个数并且要求出第K大,用权值线段树比较方便,splay也可以
而分解线段树我没听说过,所以就反过来做,线段树合并
那么就很简单了,稍微细心码一码,注意好细节,这种题小数据对了大数据也不会错
Code
#include<cstdio> #include<algorithm> #include<cstring> #define fo(i,a,b) for(int i=a;i<=b;i++) #define N 20100 #define INF 2147483647ll #define ll long long using namespace std; struct node{ int l,r,d; }t[N*100]; int ans[N*10],n,m,r ,edg[N*3][2],bz[N*3],q[N*100][3],fa ,tot,c ; void change(int v,ll i,ll j,ll x,int z) { t[v].d+=z; if(i==j) return; ll m=(i+j)/2; if(x<=m) t[v].l=t[v].l==0?++tot:t[v].l,change(t[v].l,i,m,x,z); else t[v].r=t[v].r==0?++tot:t[v].r,change(t[v].r,m+1,j,x,z); } ll get(int v,ll i,ll j,int x) { if(i==j) return i; if(t[v].d<x) return INF; ll m=(i+j)/2; if(t[t[v].r].d>=x) return get(t[v].r,m+1,j,x); else return get(t[v].l,i,m,x-t[t[v].r].d); } void hb(int v1,int v2,ll i,ll j) { if(i==j) {t[v1].d+=t[v2].d;return;} ll m=(i+j)/2; if(t[t[v1].l].d==0) t[v1].l=t[v2].l; else if(t[t[v2].l].d!=0) hb(t[v1].l,t[v2].l,i,m); if(t[t[v1].r].d==0) t[v1].r=t[v2].r; else if(t[t[v2].r].d!=0) hb(t[v1].r,t[v2].r,m+1,j); t[v1].d=t[t[v1].l].d+t[t[v1].r].d; } int gf(int x){return fa[x]==0?x:fa[x]=gf(fa[x]);} void he(int x,int y) { x=gf(x),y=gf(y); if(x==y) return; fa[y]=x; hb(r[x],r[y],1,INF+INF); } int main() { scanf("%d%d",&n,&m); fo(i,1,n) scanf("%d",&c[i]); fo(i,1,m) scanf("%d%d\n",&edg[i][0],&edg[i][1]); int i=0; while(1) { char ch;scanf("%c",&ch); if(ch=='E') break; i++; if(ch=='D') q[i][0]=0,scanf("%d\n",&q[i][1]),bz[q[i][1]]=1; if(ch=='C') q[i][0]=1,scanf("%d%d\n",&q[i][1],&q[i][2]),swap(c[q[i][1]],q[i][2]); if(ch=='Q') q[i][0]=2,scanf("%d%d\n",&q[i][1],&q[i][2]),ans[0]++; } fo(i,1,n) r[i]=++tot,change(r[i],1,INF+INF,c[i]+INF,1); fo(i,1,m) if(bz[i]==0) he(edg[i][0],edg[i][1]); int at=ans[0]; for(;i;i--) { if(q[i][0]==0) he(edg[q[i][1]][0],edg[q[i][1]][1]); if(q[i][0]==1) { int rt=r[gf(q[i][1])]; change(rt,1,INF+INF,c[q[i][1]]+INF,-1); change(rt,1,INF+INF,q[i][2]+INF,1); c[q[i][1]]=q[i][2]; } if(q[i][0]==2) ans[ans[0]--]=(int)(get(r[gf(q[i][1])],1,INF+INF,q[i][2])-INF); } fo(i,1,at) printf("%d\n",ans[i]); }
相关文章推荐
- 【NOIP2017提高组模拟6.27】C
- 【NOIP2017提高组模拟6.27】B
- 【NOIP2017提高组模拟12.18】A
- JZOJ5358【NOIP2017提高A组模拟9.12】BBQ
- 【NOIP2017提高A组模拟7.8】为了爱情 八数码拓展
- 【NOIP2017提高A组模拟10.8】Star Way To Heaven(欧几里得距离最小生成树Prim做法)
- 【NOIP2017提高组模拟12.17】向再见说再见
- 【NOIP2017提高组模拟12.18】B
- 【NOIP2017提高A组模拟8.16】花花的森林
- 空【NOIP2017提高A组模拟8.24】
- JZOJ 100035【NOIP2017提高A组模拟7.10】区间
- 【NOIP2017提高A组模拟7.13】第K小数
- 【NOIP2017提高组模拟12.10】幻魔皇
- 【NOIP2017提高组模拟12.18】C
- 【NOIP2017提高A组模拟9.7】计数题
- 【NOIP2017提高A组模拟9.23】碎
- 【NOIP2017提高组模拟12.10】神炎皇
- 【NOIP2017提高A组模拟8.23】密码
- JZOJ5347【NOIP2017提高A组模拟9.5】遥远的金字塔 斜率优化 DP
- 【NOIP2017提高A组模拟10.7】Adore