【BZOJ 2333 】[SCOI2011]棘手的操作(离线+线段树|可并堆-左偏树)
2333: [SCOI2011]棘手的操作
Description
有N个节点,标号从1到N,这N个节点一开始相互不连通。第i个节点的初始权值为a[i],接下来有如下一些操作:
U x y: 加一条边,连接第x个节点和第y个节点
A1 x v: 将第x个节点的权值增加v
A2 x v: 将第x个节点所在的连通块的所有节点的权值都增加v
A3 v: 将所有节点的权值都增加v
F1 x: 输出第x个节点当前的权值
F2 x: 输出第x个节点所在的连通块中,权值最大的节点的权值
F3: 输出所有节点中,权值最大的节点的权值
Input
输入的第一行是一个整数N,代表节点个数。
接下来一行输入N个整数,a[1], a[2], …, a[N],代表N个节点的初始权值。
再下一行输入一个整数Q,代表接下来的操作数。
最后输入Q行,每行的格式如题目描述所示。
Output
对于操作F1, F2, F3,输出对应的结果,每个结果占一行。
Sample Input
30 0 0
8
A1 3 -20
A1 2 20
U 1 3
A2 1 10
F1 3
F2 3
A3 -10
F3
Sample Output
-1010
10
HINT
对于30%的数据,保证 N<=100,Q<=10000
对于80%的数据,保证 N<=100000,Q<=100000
对于100%的数据,保证 N<=300000,Q<=300000
对于所有的数据,保证输入合法,并且 -1000<=v, a[1], a[2], …, a[N]<=1000
【分析】
这题不知道算不算有想法?
还是看了题解,其实也不是很难想,可能是我做的题太少了。 【不会可并堆ORZ】
然后这一题可以离线,因为add的是联通块,而且一旦union也就不会分开了,所以就会希望可以把点重新编号,联通块的编号在一个区间里(因为可以离线)。
所以,先预处理,建一棵合并过程的树,用并查集维护,即连接两个联通块时新建一个点,左右孩子连两个连通块的fa,用dfs序,进行查询,修改。【orz奥爷爷
- #include<cstdio>
- #include<cstdlib>
- #include<cstring>
- #include<iostream>
- #include<algorithm>
- #include<cmath>
- #include<vector>
- using namespace std;
- #define Maxn 300010
- int son[*Maxn][];
- int a[Maxn],fa[Maxn*]/*,f[Maxn*2]*/,tot;
- char s[];
- int mymax(int x,int y) {return x>y?x:y;}
- struct hp
- {
- int op,x,y,id;
- }q[Maxn];int ql;
- int ffa(int x)
- {
- if(x!=fa[x]) fa[x]=ffa(fa[x]);
- return fa[x];
- }
- int n;
- void init()
- {
- scanf("%d",&n);
- for(int i=;i<=n;i++) scanf("%d",&a[i]);
- for(int i=;i<=n;i++) fa[i]=i;tot=n;
- int m;
- scanf("%d",&m);
- ql=;
- memset(son,,sizeof(son));
- for(int i=;i<=m;i++)
- {
- scanf("%s",s);
- int x,y;
- if(s[]=='U')
- {
- scanf("%d%d",&x,&y);
- if(ffa(x)==ffa(y)) continue;
- tot++;
- son[tot][]=ffa(x);son[tot][]=ffa(y);
- fa[tot]=tot;
- fa[ffa(x)]=tot;fa[ffa(y)]=tot;
- }
- else if(s[]=='A'&&s[]=='')
- {
- scanf("%d%d",&x,&y);
- q[++ql].op=;q[ql].x=x;q[ql].y=y;
- }
- else if(s[]=='A'&&s[]=='')
- {
- scanf("%d%d",&x,&y);
- q[++ql].op=;q[ql].x=x;q[ql].y=y;q[ql].id=ffa(x);
- }
- else if(s[]=='A')
- {
- scanf("%d",&x);
- q[++ql].op=;q[ql].x=x;
- }
- else if(s[]=='F'&&s[]=='')
- {
- scanf("%d",&x);
- q[++ql].op=;q[ql].x=x;
- }
- else if(s[]=='F'&&s[]=='')
- {
- scanf("%d",&x);
- q[++ql].op=;q[ql].x=x;q[ql].id=ffa(x);
- }
- else
- {
- q[++ql].op=;
- }
- }
- }
- int cnt,dfn[Maxn],lf[*Maxn],rt[*Maxn];
- void dfs(int x)
- {
- if(x<=n)
- {
- dfn[x]=++cnt;
- lf[x]=rt[x]=dfn[x];
- return;
- }
- dfs(son[x][]);lf[x]=lf[son[x][]];
- dfs(son[x][]);rt[x]=rt[son[x][]];
- }
- struct node
- {
- int l,r,lc,rc,mx;
- int lazy;
- }t[Maxn*];int len;
- void upd(int x)
- {
- if(t[x].lazy==) return;
- t[x].mx+=t[x].lazy;
- if(t[x].l!=t[x].r)
- {
- int lc=t[x].lc,rc=t[x].rc;
- t[lc].lazy+=t[x].lazy;
- t[rc].lazy+=t[x].lazy;
- }
- t[x].lazy=;
- }
- int build(int l,int r)
- {
- int x=++len;
- t[x].l=l;t[x].r=r;t[x].mx=;
- t[x].lazy=;
- if(l!=r)
- {
- int mid=(l+r)>>;
- t[x].lc=build(l,mid);
- t[x].rc=build(mid+,r);
- }
- else t[x].lc=t[x].rc=;
- return x;
- }
- void add(int x,int l,int r,int y)
- {
- if(y==) return;
- if(t[x].l==l&&t[x].r==r)
- {
- t[x].lazy+=y;
- return;
- }
- upd(x);
- int mid=(t[x].l+t[x].r)>>;
- if(r<=mid) add(t[x].lc,l,r,y);
- else if(l>mid) add(t[x].rc,l,r,y);
- else
- {
- add(t[x].lc,l,mid,y);
- add(t[x].rc,mid+,r,y);
- }
- int lc=t[x].lc,rc=t[x].rc;
- upd(lc);upd(rc);
- t[x].mx=mymax(t[lc].mx,t[rc].mx);
- }
- int query(int x,int l,int r)
- {
- upd(x);
- if(t[x].l==l&&t[x].r==r) return t[x].mx;
- int mid=(t[x].l+t[x].r)>>;
- if(r<=mid) return query(t[x].lc,l,r);
- else if(l>mid) return query(t[x].rc,l,r);
- else return mymax(query(t[x].lc,l,mid),query(t[x].rc,mid+,r));
- }
- int main()
- {
- init();
- len=;
- build(,tot);
- cnt=;int ad=;
- for(int i=;i<=tot;i++) if(ffa(i)==i)
- {
- dfs(i);
- }
- for(int i=;i<=n;i++) add(,dfn[i],dfn[i],a[i]);
- for(int i=;i<=ql;i++)
- {
- if(q[i].op==)
- {
- // printf("add %d %d %d\n",dfn[q[i].x],dfn[q[i].x],q[i].y);
- add(,dfn[q[i].x],dfn[q[i].x],q[i].y);
- }
- else if(q[i].op==)
- {
- // printf("add %d %d %d\n",lf[q[i].id],rt[q[i].id],q[i].y);
- add(,lf[q[i].id],rt[q[i].id],q[i].y);
- }
- else if(q[i].op==)
- {
- ad+=q[i].x;
- }
- else if(q[i].op==)
- {
- // printf("ask %d %d\n",dfn[q[i].x],dfn[q[i].x]);
- int now=query(,dfn[q[i].x],dfn[q[i].x]);
- printf("%d\n",now+ad);
- }
- else if(q[i].op==)
- {
- // printf("ask %d %d\n",lf[q[i].id],rt[q[i].id]);
- int now=query(,lf[q[i].id],rt[q[i].id]);
- printf("%d\n",now+ad);
- }
- else if(q[i].op==)
- {
- int now=query(,,cnt);
- printf("%d\n",now+ad);
- }
- }
- return ;
- }
2016-11-10 09:49:34
学了可并堆我回来更新啦哈哈哈哈【傻。。
【感觉这个题号在嘲笑我><】
左偏树,还要带lazy标记,还要加一个set,呵呵呵,因为看不懂别人的,所以自己YYYYY,所以就乱搞了一整天+很多呆滞的moment。。
细节真心超多,
我搞了个rt(用并查集维护),还有一个fa(左偏树中直属父亲)。
fa,从下往上找,然后从上往下pushdown那里好像有点慢,不过我看黄学长这里也是这样的。【表示左偏树做法比离线慢呐~~
A1操作先删点,再加点,细节很多!!!【因为我乱搞呵呵呵呵
= =或许应该看这个题解:http://blog.csdn.net/charlie_pyc/article/details/20830305
- #include<cstdio>
- #include<cstdlib>
- #include<cstring>
- #include<iostream>
- #include<algorithm>
- #include<set>
- using namespace std;
- #define Maxn 300010
- #define INF 0x7fffffff
- int mymax(int x,int y) {return x>y?x:y;}
- int a[Maxn],all=;
- int n,q,cnt;
- char s[];
- multiset<int > ss;
- struct node
- {
- int x,lc,rc,dis,fa,rt;
- int lazy;
- }t[Maxn];
- void upd(int x)
- {
- t[x].lc=t[x].rc=;
- t[x].dis=;t[x].lazy=;
- t[x].fa=;
- }
- void era(int x)
- {
- multiset<int>:: iterator it;
- it=ss.find(x);
- ss.erase(it);
- }
- int v[Maxn];
- struct Ltree
- {
- int rtt(int x)
- {
- if(t[x].rt!=x) t[x].rt=rtt(t[x].rt);
- return t[x].rt;
- }
- void pushdown(int x)
- {
- if(t[x].lc) t[t[x].lc].lazy+=t[x].lazy;
- if(t[x].rc) t[t[x].rc].lazy+=t[x].lazy;
- t[x].x+=t[x].lazy;
- t[x].lazy=;
- }
- int merge(int x,int y)
- {
- if(x==||y==) return x+y;
- pushdown(x);pushdown(y);
- if(t[x].x<t[y].x) swap(x,y);
- t[x].rc=merge(t[x].rc,y);
- if(t[x].rc) t[t[x].rc].fa=x;
- if(t[t[x].lc].dis<t[t[x].rc].dis) swap(t[x].lc,t[x].rc);
- t[x].dis=t[t[x].rc].dis+;
- return x;
- }
- void sol(int x)
- {
- v[]=;
- while(x) v[++v[]]=x,x=t[x].fa;
- while(v[]) pushdown(v[v[]--]);
- }
- int add(int x,int y)
- {
- int xx=rtt(x);
- pushdown(xx);era(t[xx].x);sol(x);
- int nw=merge(t[x].lc,t[x].rc);
- if(t[x].fa)
- {
- if(t[t[x].fa].lc==x) t[t[x].fa].lc=nw;
- else t[t[x].fa].rc=nw;
- }
- if(nw)
- {
- t[nw].fa=t[x].fa;
- }
- t[x].x+=y;upd(x);
- if(x!=xx) nw=merge(x,xx);
- else nw=merge(x,nw);
- t[x].rt=t[xx].rt=t[nw].rt=nw;
- pushdown(nw);
- ss.insert(t[nw].x);
- }
- }heap;
- int main()
- {
- scanf("%d",&n);
- t[].dis=-;
- for(int i=;i<=n;i++) scanf("%d",&a[i]);
- for(int i=;i<=n;i++) upd(i),t[i].x=a[i],t[i].fa=,t[i].rt=i;
- ss.clear();
- for(int i=;i<=n;i++) ss.insert(a[i]);
- scanf("%d",&q);
- for(int i=;i<=q;i++)
- {
- scanf("%s",s);
- int x,y;
- if(s[]=='U')
- {
- scanf("%d%d",&x,&y);
- int xx=heap.rtt(x),yy=heap.rtt(y);
- if(xx==yy) continue;
- heap.pushdown(xx);era(t[xx].x);
- heap.pushdown(yy);era(t[yy].x);
- int nw=heap.merge(xx,yy);
- t[xx].rt=t[yy].rt=nw;
- heap.pushdown(nw);ss.insert(t[nw].x);
- }
- else if(s[]=='A')
- {
- if(s[]=='')
- {
- scanf("%d%d",&x,&y);
- heap.add(x,y);
- }
- else if(s[]=='')
- {
- scanf("%d%d",&x,&y);
- int xx=heap.rtt(x);
- heap.pushdown(xx);
- era(t[xx].x);
- t[xx].lazy+=y;
- heap.pushdown(xx);
- ss.insert(t[xx].x);
- }
- else
- {
- scanf("%d",&x);
- all+=x;
- }
- }
- else
- {
- if(s[]=='')
- {
- scanf("%d",&x);
- heap.sol(x);
- heap.pushdown(x);
- printf("%d\n",t[x].x+all);
- }
- else if(s[]=='')
- {
- scanf("%d",&x);
- int xx=heap.rtt(x);
- heap.pushdown(xx);
- printf("%d\n",t[xx].x+all);
- }
- else
- {
- printf("%d\n",*(--ss.end())+all);
- }
- }
- }
- return ;
- }
2017-01-20 17:05:47
在后面再写一题:(因为没A就插在AC的题目后面吧)
HDU5454
【题意】
n*n的矩阵,每次对连续的一段对角线全部加1,每次询问一个子矩阵的和(n<=200000)
【分析】
跟那道矩阵旋转的线段树维护有点像。要对矩阵的对角线以及旋转有很深的理解才行啊。。。
对于左斜线来说,加的值都是一样的,右斜线也是。所以可以分开维护。
一个矩形就可以分成一个平行四边形和两个三角形咯,平行四边形那里对角线长度相等,可以求和,三角形的话,对角线长度是递增的,所以可以维护类似a[i]*i的前缀和。。、
超难打ORZ .....
放个还没有AC的代码:
- #include<cstdio>
- #include<cstdlib>
- #include<cstring>
- #include<iostream>
- #include<algorithm>
- #include<cmath>
- using namespace std;
- #define INF 0xfffffff
- #define Maxn 200010
- struct node
- {
- int l,r,lc,rc,f[],f1[],f2[];
- int lazy[];
- }t[*Maxn];int len;
- int n,m;
- int myabs(int x) {return x>?x:-x;}
- int mymin(int x,int y) {return x<y?x:y;}
- int mymax(int x,int y) {return x>y?x:y;}
- int build(int l,int r)
- {
- int x=++len;
- t[x].l=l;t[x].r=r;
- t[x].f[]=t[x].f[]=t[x].f1[]=t[x].f1[]=t[x].f2[]=t[x].f2[]=;
- t[x].lazy[]=t[x].lazy[]=;
- if(l!=r)
- {
- int mid=(l+r)>>;
- t[x].lc=build(l,mid);
- t[x].rc=build(mid+,r);
- }
- else t[x].lc=t[x].rc=;
- return x;
- }
- int gsum(int l,int r)
- {
- return (l+r)*(r-l+)/;
- }
- void upd(int x,int p)
- {
- if(t[x].lazy[p]==) return;
- int lc=t[x].lc,rc=t[x].rc;
- t[x].f[p]+=t[x].lazy[p]*(t[x].r-t[x].l+);
- t[x].f1[p]+=t[x].lazy[p]*gsum(t[x].l,t[x].r);
- t[x].f2[p]+=t[x].lazy[p]*gsum(*n-t[x].r,*n-t[x].l);
- t[lc].lazy[p]+=t[x].lazy[p];t[rc].lazy[p]+=t[x].lazy[p];
- t[x].lazy[p]=;
- return;
- }
- void change(int x,int l,int r,int p)
- {
- if(t[x].l==l&&t[x].r==r)
- {
- t[x].lazy[p]++;
- return;
- }
- upd(x,p);
- int mid=(t[x].l+t[x].r)>>;
- if(r<=mid) change(t[x].lc,l,r,p);
- else if(l>mid) change(t[x].rc,l,r,p);
- else
- {
- change(t[x].lc,l,mid,p);
- change(t[x].rc,mid+,r,p);
- }
- int lc=t[x].lc,rc=t[x].rc;
- upd(lc,p);
- upd(rc,p);
- t[x].f[p]=t[lc].f[p]+t[rc].f[p];
- t[x].f1[p]=t[lc].f1[p]+t[rc].f1[p];
- t[x].f2[p]=t[lc].f2[p]+t[rc].f2[p];
- }
- int query(int x,int l,int r,int p,int op)
- {
- int tt;
- if(l>r) tt=l,l=r,r=tt;
- if(r>*n-) r=*n-;
- if(l<) l=;
- upd(x,p);
- if(t[x].l==l&&t[x].r==r)
- {
- if(op==) return t[x].f1[p];
- else if(op==) return t[x].f2[p];
- else return t[x].f[p];
- }
- int mid=(t[x].l+t[x].r)>>;
- if(r<=mid) return query(t[x].lc,l,r,p,op);
- else if(l>mid) return query(t[x].rc,l,r,p,op);
- else return query(t[x].lc,l,mid,p,op)+query(t[x].rc,mid+,r,p,op);
- }
- int main()
- {
- int T,kase=;
- scanf("%d",&T);
- while(T--)
- {
- scanf("%d%d",&n,&m);
- len=;
- build(,*n-);
- printf("Case #%d:\n",++kase);
- for(int i=;i<=m;i++)
- {
- int opt;
- scanf("%d",&opt);
- int l,r;
- if(opt==)
- {
- scanf("%d%d",&l,&r);
- l--;r--;
- printf("%d %d %d\n",l,r,);
- change(,l,r,);
- }
- else if(opt==)
- {
- scanf("%d%d",&l,&r);
- l+=n;r+=n;
- printf("%d %d %d\n",l,r,);
- change(,l,r,);
- }
- else
- {
- int a,b;
- scanf("%d%d%d%d",&l,&a,&r,&b);
- int ans=;
- ans+=(query(,a+r-,l+b-,,)+query(,l-r+n,a-b+n,,))*mymin(a-l+,b-r+);
- //zhu
- int kk=mymin(a+r-,l+b-);
- ans+=query(,l+r-,kk,,)-query(,l+r-,kk,,)*(l+r-);//左上
- kk=mymax(a+r,l+b);
- ans+=query(,kk,a+b-,,)-query(,kk,a+b-,,)*(*n-(a+b-)-);//右下
- //fu
- kk=mymin(a-b+n-,l-r+n-);
- ans+=query(,l-b+n,kk,,)-query(,l-b+n,kk,,)*(l-b+n-);//右上
- kk=mymax(a-b+n+,l-r+n+);
- ans+=query(,kk,a-r+n,,)-query(,kk,a-r+n,,)*(*n-(a-r+n)-);//左下
- printf("%d\n",ans);
- }
- }
- }
- return ;
- }
有空的话,再填坑吧。。
2016-11-10 09:54:11
【BZOJ 2333 】[SCOI2011]棘手的操作(离线+线段树|可并堆-左偏树)的更多相关文章
- 2333: [SCOI2011]棘手的操作[离线线段树]
2333: [SCOI2011]棘手的操作 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 2325 Solved: 909[Submit][Stat ...
- BZOJ 2333 SCOI2011 棘手的操作 并查集+可并堆
题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=2333 ..题意概述就不写了,各位老爷如果是看着玩的可以去搜一下,如果是做题找来的也知道题干 ...
- bzoj 2333 [SCOI2011]棘手的操作 —— 可并堆
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2333 稍微复杂,参考了博客:http://hzwer.com/5780.html 用 set ...
- BZOJ 2333: [SCOI2011]棘手的操作 可并堆 左偏树 set
https://www.lydsy.com/JudgeOnline/problem.php?id=2333 需要两个结构分别维护每个连通块的最大值和所有连通块最大值中的最大值,可以用两个可并堆实现,也 ...
- BZOJ 2333: [SCOI2011]棘手的操作
题目描述 真的是个很棘手的操作.. 注意每删除一个点,就需要clear一次. #include<complex> #include<cstdio> using namespac ...
- BZOJ 2333 [SCOI2011]棘手的操作 (可并堆)
码农题.. 很显然除了两个全局操作都能用可并堆完成 全局最大值用个multiset记录,每次合并时搞一搞就行了 注意使用multiset删除元素时 如果直接delete一个值,会把和这个值相同的所有元 ...
- 2333: [SCOI2011]棘手的操作[写不出来]
2333: [SCOI2011]棘手的操作 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 1979 Solved: 772[Submit][Stat ...
- 2333: [SCOI2011]棘手的操作[我不玩了]
2333: [SCOI2011]棘手的操作 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 1979 Solved: 772[Submit][Stat ...
- 【BZOJ】2333: [SCOI2011]棘手的操作
http://www.lydsy.com/JudgeOnline/problem.php?id=2333 题意: 有N个节点,标号从1到N,这N个节点一开始相互不连通.第i个节点的初始权值为a[i], ...
随机推荐
- [学习笔记]最小割之最小点权覆盖&&最大点权独立集
最小点权覆盖 给出一个二分图,每个点有一个非负点权 要求选出一些点构成一个覆盖,问点权最小是多少 建模: S到左部点,容量为点权 右部点到T,容量为点权 左部点到右部点的边,容量inf 求最小割即可. ...
- 洛谷P2568 GCD (欧拉函数/莫比乌斯反演)
P2568 GCD 题目描述 给定整数N,求1<=x,y<=N且Gcd(x,y)为素数的数对(x,y)有多少对. 输入输出格式 输入格式: 一个整数N 输出格式: 答案 输入输出样例 输入 ...
- vue2学习篇一 $mount()手动挂载
$mount()手动挂载 //当Vue实例没有el属性时,则该实例尚没有挂载到某个dom中: //假如需要延迟挂载,可以在之后手动调用vm.$mount()方法来挂载.例如: new Vue({ // ...
- Jquery 获取checkbox的checked问题以及解决方案
转载自:http://www.cnblogs.com/-run/archive/2011/11/16/2251250.html 这个郁闷了,今天写这个功能的时候发现了问题,上网找了好多资料对照,更加纠 ...
- 栈与递归的实现(Hanoi塔问题等等)
函数中有直接或间接地调用自身函数的语句,这样的函数称为递归函数.递归函数用 得好,可简化编程工作.但函数自己调用自己,有可能造成死循环.为了避免死循环,要 做到两点: (1) 降阶.递归函数虽然调用自 ...
- [05]Git查看、删除、重命名远程分支和tag
Git查看.删除.重命名远程分支和tag 2015-06-15:加入姊妹篇: 2013-11-06:加入重命名远程分支的内容: 2013-01-09:加入删除远程tag的内容. 姊妹篇:使用Git.G ...
- js实现日历
有这样一个普通的日历需求 第一反应就是找插件,结果找到了,但是改起来非常麻烦,然后查下实现的原理,发现原来很简单,于是自己实现了一个. 首先分析一下这个组件,每页显示的是 当前月的所有日期及所占据的行 ...
- hive向表格中插入数据并分析语句
1,---导入mds_imei_month_info ; //最大的动态分区表 set hive.support.concurrency=false; //是否支持并发 ; //each mapper ...
- [BZOJ3261&BZOJ3166]可持久化trie树及其应用
可持久化trie树 可持久化trie树现在想来是比较好理解的了,但却看了一个下午... 相当于对于每个状态建立一条链(或者说一棵trie),求解的时候只要让两个点按照相同的步子走然后看sum的大小关系 ...
- 【STSRM12】整除
[题意]给定长度为n的序列A,求最长的区间满足区间内存在数字能整除区间所有数字,同时求所有方案.n<=5*10^5,Ai<2^31. [算法]数论??? [题解]首先一个区间的基准数一定是 ...