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
3
0 0 0
8
A1 3 -20
A1 2 20
U 1 3
A2 1 10
F1 3
F2 3
A3 -10
F3
Sample Output
-10
10
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奥爷爷
1 #include2 #include 3 #include 4 #include 5 #include 6 #include 7 #include 8 using namespace std; 9 #define Maxn 300010 10 11 int son[2*Maxn][2]; 12 int a[Maxn],fa[Maxn*2]/*,f[Maxn*2]*/,tot; 13 char s[10]; 14 15 int mymax(int x,int y) {return x>y?x:y;} 16 17 struct hp 18 { 19 int op,x,y,id; 20 }q[Maxn];int ql; 21 22 int ffa(int x) 23 { 24 if(x!=fa[x]) fa[x]=ffa(fa[x]); 25 return fa[x]; 26 } 27 28 int n; 29 void init() 30 { 31 scanf("%d",&n); 32 for(int i=1;i<=n;i++) scanf("%d",&a[i]); 33 for(int i=1;i<=n;i++) fa[i]=i;tot=n; 34 int m; 35 scanf("%d",&m); 36 ql=0; 37 memset(son,0,sizeof(son)); 38 for(int i=1;i<=m;i++) 39 { 40 scanf("%s",s); 41 int x,y; 42 if(s[0]=='U') 43 { 44 scanf("%d%d",&x,&y); 45 if(ffa(x)==ffa(y)) continue; 46 tot++; 47 son[tot][0]=ffa(x);son[tot][1]=ffa(y); 48 fa[tot]=tot; 49 fa[ffa(x)]=tot;fa[ffa(y)]=tot; 50 } 51 else if(s[0]=='A'&&s[1]=='1') 52 { 53 scanf("%d%d",&x,&y); 54 q[++ql].op=0;q[ql].x=x;q[ql].y=y; 55 } 56 else if(s[0]=='A'&&s[1]=='2') 57 { 58 scanf("%d%d",&x,&y); 59 q[++ql].op=1;q[ql].x=x;q[ql].y=y;q[ql].id=ffa(x); 60 } 61 else if(s[0]=='A') 62 { 63 scanf("%d",&x); 64 q[++ql].op=2;q[ql].x=x; 65 66 } 67 else if(s[0]=='F'&&s[1]=='1') 68 { 69 scanf("%d",&x); 70 q[++ql].op=3;q[ql].x=x; 71 } 72 else if(s[0]=='F'&&s[1]=='2') 73 { 74 scanf("%d",&x); 75 q[++ql].op=4;q[ql].x=x;q[ql].id=ffa(x); 76 } 77 else 78 { 79 q[++ql].op=5; 80 } 81 } 82 } 83 84 int cnt,dfn[Maxn],lf[2*Maxn],rt[2*Maxn]; 85 void dfs(int x) 86 { 87 if(x<=n) 88 { 89 dfn[x]=++cnt; 90 lf[x]=rt[x]=dfn[x]; 91 return; 92 } 93 dfs(son[x][0]);lf[x]=lf[son[x][0]]; 94 dfs(son[x][1]);rt[x]=rt[son[x][1]]; 95 } 96 97 struct node 98 { 99 int l,r,lc,rc,mx; 100 int lazy; 101 }t[Maxn*4];int len; 102 103 void upd(int x) 104 { 105 if(t[x].lazy==0) return; 106 t[x].mx+=t[x].lazy; 107 if(t[x].l!=t[x].r) 108 { 109 int lc=t[x].lc,rc=t[x].rc; 110 t[lc].lazy+=t[x].lazy; 111 t[rc].lazy+=t[x].lazy; 112 } 113 t[x].lazy=0; 114 } 115 116 int build(int l,int r) 117 { 118 int x=++len; 119 t[x].l=l;t[x].r=r;t[x].mx=0; 120 t[x].lazy=0; 121 if(l!=r) 122 { 123 int mid=(l+r)>>1; 124 t[x].lc=build(l,mid); 125 t[x].rc=build(mid+1,r); 126 } 127 else t[x].lc=t[x].rc=0; 128 return x; 129 } 130 131 void add(int x,int l,int r,int y) 132 { 133 if(y==0) return; 134 if(t[x].l==l&&t[x].r==r) 135 { 136 t[x].lazy+=y; 137 return; 138 } 139 upd(x); 140 int mid=(t[x].l+t[x].r)>>1; 141 if(r<=mid) add(t[x].lc,l,r,y); 142 else if(l>mid) add(t[x].rc,l,r,y); 143 else 144 { 145 add(t[x].lc,l,mid,y); 146 add(t[x].rc,mid+1,r,y); 147 } 148 int lc=t[x].lc,rc=t[x].rc; 149 upd(lc);upd(rc); 150 t[x].mx=mymax(t[lc].mx,t[rc].mx); 151 } 152 153 int query(int x,int l,int r) 154 { 155 upd(x); 156 if(t[x].l==l&&t[x].r==r) return t[x].mx; 157 int mid=(t[x].l+t[x].r)>>1; 158 if(r<=mid) return query(t[x].lc,l,r); 159 else if(l>mid) return query(t[x].rc,l,r); 160 else return mymax(query(t[x].lc,l,mid),query(t[x].rc,mid+1,r)); 161 } 162 163 int main() 164 { 165 init(); 166 len=0; 167 build(1,tot); 168 cnt=0;int ad=0; 169 for(int i=1;i<=tot;i++) if(ffa(i)==i) 170 { 171 dfs(i); 172 } 173 for(int i=1;i<=n;i++) add(1,dfn[i],dfn[i],a[i]); 174 for(int i=1;i<=ql;i++) 175 { 176 if(q[i].op==0) 177 { 178 // printf("add %d %d %d\n",dfn[q[i].x],dfn[q[i].x],q[i].y); 179 add(1,dfn[q[i].x],dfn[q[i].x],q[i].y); 180 } 181 else if(q[i].op==1) 182 { 183 // printf("add %d %d %d\n",lf[q[i].id],rt[q[i].id],q[i].y); 184 add(1,lf[q[i].id],rt[q[i].id],q[i].y); 185 } 186 else if(q[i].op==2) 187 { 188 ad+=q[i].x; 189 } 190 else if(q[i].op==3) 191 { 192 // printf("ask %d %d\n",dfn[q[i].x],dfn[q[i].x]); 193 int now=query(1,dfn[q[i].x],dfn[q[i].x]); 194 printf("%d\n",now+ad); 195 } 196 else if(q[i].op==4) 197 { 198 // printf("ask %d %d\n",lf[q[i].id],rt[q[i].id]); 199 int now=query(1,lf[q[i].id],rt[q[i].id]); 200 printf("%d\n",now+ad); 201 } 202 else if(q[i].op==5) 203 { 204 int now=query(1,1,cnt); 205 printf("%d\n",now+ad); 206 } 207 } 208 return 0; 209 }
2016-11-10 09:49:34
学了可并堆我回来更新啦哈哈哈哈【傻。。
【感觉这个题号在嘲笑我><】
左偏树,还要带lazy标记,还要加一个set,呵呵呵,因为看不懂别人的,所以自己YYYYY,所以就乱搞了一整天+很多呆滞的moment。。
细节真心超多,
我搞了个rt(用并查集维护),还有一个fa(左偏树中直属父亲)。
fa,从下往上找,然后从上往下pushdown那里好像有点慢,不过我看黄学长这里也是这样的。【表示左偏树做法比离线慢呐~~
A1操作先删点,再加点,细节很多!!!【因为我乱搞呵呵呵呵
= =或许应该看这个题解:http://blog.csdn.net/charlie_pyc/article/details/20830305
1 #include2 #include 3 #include 4 #include 5 #include 6 #include<set> 7 using namespace std; 8 #define Maxn 300010 9 #define INF 0x7fffffff 10 11 int mymax(int x,int y) {return x>y?x:y;} 12 13 int a[Maxn],all=0; 14 int n,q,cnt; 15 char s[100]; 16 17 multiset<int > ss; 18 19 struct node 20 { 21 int x,lc,rc,dis,fa,rt; 22 int lazy; 23 }t[Maxn]; 24 25 void upd(int x) 26 { 27 t[x].lc=t[x].rc=0; 28 t[x].dis=0;t[x].lazy=0; 29 t[x].fa=0; 30 } 31 32 void era(int x) 33 { 34 multiset<int>:: iterator it; 35 it=ss.find(x); 36 ss.erase(it); 37 } 38 39 40 int v[Maxn]; 41 struct Ltree 42 { 43 int rtt(int x) 44 { 45 if(t[x].rt!=x) t[x].rt=rtt(t[x].rt); 46 return t[x].rt; 47 } 48 void pushdown(int x) 49 { 50 if(t[x].lc) t[t[x].lc].lazy+=t[x].lazy; 51 if(t[x].rc) t[t[x].rc].lazy+=t[x].lazy; 52 t[x].x+=t[x].lazy; 53 t[x].lazy=0; 54 } 55 int merge(int x,int y) 56 { 57 if(x==0||y==0) return x+y; 58 pushdown(x);pushdown(y); 59 if(t[x].x<t[y].x) swap(x,y); 60 t[x].rc=merge(t[x].rc,y); 61 if(t[x].rc) t[t[x].rc].fa=x; 62 if(t[t[x].lc].dis<t[t[x].rc].dis) swap(t[x].lc,t[x].rc); 63 t[x].dis=t[t[x].rc].dis+1; 64 return x; 65 } 66 void sol(int x) 67 { 68 v[0]=0; 69 while(x) v[++v[0]]=x,x=t[x].fa; 70 while(v[0]) pushdown(v[v[0]--]); 71 } 72 int add(int x,int y) 73 { 74 int xx=rtt(x); 75 pushdown(xx);era(t[xx].x);sol(x); 76 int nw=merge(t[x].lc,t[x].rc); 77 if(t[x].fa) 78 { 79 if(t[t[x].fa].lc==x) t[t[x].fa].lc=nw; 80 else t[t[x].fa].rc=nw; 81 } 82 if(nw) 83 { 84 t[nw].fa=t[x].fa; 85 } 86 t[x].x+=y;upd(x); 87 if(x!=xx) nw=merge(x,xx); 88 else nw=merge(x,nw); 89 90 t[x].rt=t[xx].rt=t[nw].rt=nw; 91 pushdown(nw); 92 ss.insert(t[nw].x); 93 } 94 }heap; 95 96 int main() 97 { 98 scanf("%d",&n); 99 t[0].dis=-1; 100 for(int i=1;i<=n;i++) scanf("%d",&a[i]); 101 for(int i=1;i<=n;i++) upd(i),t[i].x=a[i],t[i].fa=0,t[i].rt=i; 102 ss.clear(); 103 for(int i=1;i<=n;i++) ss.insert(a[i]); 104 105 scanf("%d",&q); 106 for(int i=1;i<=q;i++) 107 { 108 scanf("%s",s); 109 int x,y; 110 if(s[0]=='U') 111 { 112 scanf("%d%d",&x,&y); 113 int xx=heap.rtt(x),yy=heap.rtt(y); 114 if(xx==yy) continue; 115 heap.pushdown(xx);era(t[xx].x); 116 heap.pushdown(yy);era(t[yy].x); 117 int nw=heap.merge(xx,yy); 118 t[xx].rt=t[yy].rt=nw; 119 heap.pushdown(nw);ss.insert(t[nw].x); 120 } 121 else if(s[0]=='A') 122 { 123 if(s[1]=='1') 124 { 125 scanf("%d%d",&x,&y); 126 heap.add(x,y); 127 } 128 else if(s[1]=='2') 129 { 130 scanf("%d%d",&x,&y); 131 int xx=heap.rtt(x); 132 heap.pushdown(xx); 133 era(t[xx].x); 134 t[xx].lazy+=y; 135 heap.pushdown(xx); 136 ss.insert(t[xx].x); 137 } 138 else 139 { 140 scanf("%d",&x); 141 all+=x; 142 } 143 } 144 else 145 { 146 if(s[1]=='1') 147 { 148 scanf("%d",&x); 149 heap.sol(x); 150 heap.pushdown(x); 151 printf("%d\n",t[x].x+all); 152 } 153 else if(s[1]=='2') 154 { 155 scanf("%d",&x); 156 int xx=heap.rtt(x); 157 heap.pushdown(xx); 158 printf("%d\n",t[xx].x+all); 159 } 160 else 161 { 162 printf("%d\n",*(--ss.end())+all); 163 } 164 } 165 } 166 return 0; 167 }
2017-01-20 17:05:47
在后面再写一题:(因为没A就插在AC的题目后面吧)
HDU5454
【题意】
n*n的矩阵,每次对连续的一段对角线全部加1,每次询问一个子矩阵的和(n<=200000)
【分析】
跟那道矩阵旋转的线段树维护有点像。要对矩阵的对角线以及旋转有很深的理解才行啊。。。
对于左斜线来说,加的值都是一样的,右斜线也是。所以可以分开维护。
一个矩形就可以分成一个平行四边形和两个三角形咯,平行四边形那里对角线长度相等,可以求和,三角形的话,对角线长度是递增的,所以可以维护类似a[i]*i的前缀和。。、
超难打ORZ .....
放个还没有AC的代码:
1 #include2 #include 3 #include 4 #include 5 #include 6 #include 7 using namespace std; 8 #define INF 0xfffffff 9 #define Maxn 200010 10 11 struct node 12 { 13 int l,r,lc,rc,f[2],f1[2],f2[2]; 14 int lazy[2]; 15 }t[2*Maxn];int len; 16 17 int n,m; 18 int myabs(int x) {return x>0?x:-x;} 19 int mymin(int x,int y) {return x x:y;} 20 int mymax(int x,int y) {return x>y?x:y;} 21 22 int build(int l,int r) 23 { 24 int x=++len; 25 t[x].l=l;t[x].r=r; 26 t[x].f[0]=t[x].f[1]=t[x].f1[0]=t[x].f1[1]=t[x].f2[0]=t[x].f2[1]=0; 27 t[x].lazy[0]=t[x].lazy[1]=0; 28 if(l!=r) 29 { 30 int mid=(l+r)>>1; 31 t[x].lc=build(l,mid); 32 t[x].rc=build(mid+1,r); 33 } 34 else t[x].lc=t[x].rc=0; 35 return x; 36 } 37 38 int gsum(int l,int r) 39 { 40 return (l+r)*(r-l+1)/2; 41 } 42 43 void upd(int x,int p) 44 { 45 if(t[x].lazy[p]==0) return; 46 int lc=t[x].lc,rc=t[x].rc; 47 t[x].f[p]+=t[x].lazy[p]*(t[x].r-t[x].l+1); 48 t[x].f1[p]+=t[x].lazy[p]*gsum(t[x].l,t[x].r); 49 t[x].f2[p]+=t[x].lazy[p]*gsum(2*n-t[x].r,2*n-t[x].l); 50 t[lc].lazy[p]+=t[x].lazy[p];t[rc].lazy[p]+=t[x].lazy[p]; 51 t[x].lazy[p]=0; 52 return; 53 } 54 55 void change(int x,int l,int r,int p) 56 { 57 if(t[x].l==l&&t[x].r==r) 58 { 59 t[x].lazy[p]++; 60 return; 61 } 62 upd(x,p); 63 int mid=(t[x].l+t[x].r)>>1; 64 if(r<=mid) change(t[x].lc,l,r,p); 65 else if(l>mid) change(t[x].rc,l,r,p); 66 else 67 { 68 change(t[x].lc,l,mid,p); 69 change(t[x].rc,mid+1,r,p); 70 } 71 int lc=t[x].lc,rc=t[x].rc; 72 upd(lc,p); 73 upd(rc,p); 74 t[x].f[p]=t[lc].f[p]+t[rc].f[p]; 75 t[x].f1[p]=t[lc].f1[p]+t[rc].f1[p]; 76 t[x].f2[p]=t[lc].f2[p]+t[rc].f2[p]; 77 } 78 79 int query(int x,int l,int r,int p,int op) 80 { 81 int tt; 82 if(l>r) tt=l,l=r,r=tt; 83 if(r>2*n-1) r=2*n-1; 84 if(l<1) l=1; 85 upd(x,p); 86 if(t[x].l==l&&t[x].r==r) 87 { 88 if(op==0) return t[x].f1[p]; 89 else if(op==1) return t[x].f2[p]; 90 else return t[x].f[p]; 91 } 92 int mid=(t[x].l+t[x].r)>>1; 93 if(r<=mid) return query(t[x].lc,l,r,p,op); 94 else if(l>mid) return query(t[x].rc,l,r,p,op); 95 else return query(t[x].lc,l,mid,p,op)+query(t[x].rc,mid+1,r,p,op); 96 } 97 98 int main() 99 { 100 int T,kase=0; 101 scanf("%d",&T); 102 while(T--) 103 { 104 scanf("%d%d",&n,&m); 105 len=0; 106 build(1,2*n-1); 107 printf("Case #%d:\n",++kase); 108 for(int i=1;i<=m;i++) 109 { 110 int opt; 111 scanf("%d",&opt); 112 int l,r; 113 if(opt==1) 114 { 115 scanf("%d%d",&l,&r); 116 l--;r--; 117 printf("%d %d %d\n",l,r,0); 118 change(1,l,r,0); 119 } 120 else if(opt==2) 121 { 122 scanf("%d%d",&l,&r); 123 l+=n;r+=n; 124 printf("%d %d %d\n",l,r,1); 125 change(1,l,r,1); 126 } 127 else 128 { 129 int a,b; 130 scanf("%d%d%d%d",&l,&a,&r,&b); 131 int ans=0; 132 ans+=(query(1,a+r-1,l+b-1,0,2)+query(1,l-r+n,a-b+n,1,2))*mymin(a-l+1,b-r+1); 133 //zhu 134 int kk=mymin(a+r-2,l+b-2); 135 ans+=query(1,l+r-1,kk,0,0)-query(1,l+r-1,kk,0,2)*(l+r-2);//左上 136 kk=mymax(a+r,l+b); 137 ans+=query(1,kk,a+b-1,0,1)-query(1,kk,a+b-1,0,2)*(2*n-(a+b-1)-1);//右下 138 //fu 139 kk=mymin(a-b+n-1,l-r+n-1); 140 ans+=query(1,l-b+n,kk,1,0)-query(1,l-b+n,kk,1,2)*(l-b+n-1);//右上 141 142 kk=mymax(a-b+n+1,l-r+n+1); 143 ans+=query(1,kk,a-r+n,1,1)-query(1,kk,a-r+n,1,2)*(2*n-(a-r+n)-1);//左下 144 printf("%d\n",ans); 145 } 146 } 147 } 148 return 0; 149 }
有空的话,再填坑吧。。
2016-11-10 09:54:11