2013 UESTC ACM Training for Data Structure
又到了一年招新的时候,数据结构又是第一个专题,简要写一下本专题的解题报告
先附上本专题题目地址:2013 UESTC ACM Training for Data Structure 不是本校的同学可以先看看题目
由于题目较多,不再一一叙述题意,只是简要的说说做法再贴个代码
A题 Hotel
简单线段树,可能实现起来比较困难,不过做法是比较容易想到的
参考代码
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 5 using namespace std; 6 7 struct Interval_Tree 8 { 9 static const int N=50006; 10 struct node 11 { 12 int s, t, Lmax, Rmax, Max, tag; 13 } T[N<<2]; 14 15 inline void Fill(int id, int tag) 16 { 17 T[id].Lmax=T[id].Rmax=T[id].Max=(T[id].t-T[id].s+1)*tag; 18 } 19 20 inline void pushUp(int id) 21 { 22 T[id].Lmax=T[id<<1].Lmax; 23 if(T[id<<1].t-T[id<<1].s+1==T[id<<1].Lmax) T[id].Lmax+=T[id<<1|1].Lmax; 24 T[id].Rmax=T[id<<1|1].Rmax; 25 if(T[id<<1|1].t-T[id<<1|1].s+1==T[id<<1|1].Rmax) T[id].Rmax+=T[id<<1].Rmax; 26 T[id].Max=max(max(T[id<<1].Max, T[id<<1|1].Max), T[id<<1].Rmax+T[id<<1|1].Lmax); 27 } 28 29 inline void pushDown(int id) 30 { 31 T[id<<1].tag=T[id<<1|1].tag=T[id].tag; 32 Fill(id<<1, T[id].tag), Fill(id<<1|1, T[id].tag); 33 T[id].tag=-1; 34 } 35 36 void build(int id, int L, int R) 37 { 38 T[id].s=L, T[id].t=R, T[id].tag=-1; 39 Fill(id, 1); 40 if(L==R) return; 41 int mid=(L+R)>>1; 42 build(id<<1, L, mid), build(id<<1|1, mid+1, R); 43 } 44 45 int query(int id, int len) 46 { 47 if(T[id].Max<len) return 0; 48 if(T[id].s==T[id].t) return T[id].s; 49 if(T[id].Lmax>=len) return T[id].s; 50 if(T[id].tag!=-1) pushDown(id); 51 if(T[id<<1].Max>=len) return query(id<<1, len); 52 else if(T[id<<1].Rmax+T[id<<1|1].Lmax>=len) return T[id<<1].t-T[id<<1].Rmax+1; 53 else return query(id<<1|1, len); 54 } 55 56 void update(int id, int L, int R, int tag) 57 { 58 if(L<=T[id].s && T[id].t<=R) 59 { 60 Fill(id, T[id].tag=tag); 61 return; 62 } 63 int mid=(T[id].s+T[id].t)>>1; 64 if(T[id].tag!=-1) pushDown(id); 65 if(R<=mid) update(id<<1, L, R, tag); 66 else if(L>mid) update(id<<1|1, L, R, tag); 67 else update(id<<1, L, R, tag), update(id<<1|1, L, R, tag); 68 pushUp(id); 69 } 70 } tree; 71 72 int main() 73 { 74 int n, m; 75 scanf("%d%d", &n, &m); 76 tree.build(1, 1, n); 77 for(int i=0, a, b ,c; i<m; i++) 78 { 79 scanf("%d", &a); 80 if(a==1) 81 { 82 scanf("%d", &b); 83 int c=tree.query(1, b); 84 printf("%d\n", c); 85 if(c!=0) tree.update(1, c, c+b-1, 0); 86 } 87 else 88 { 89 scanf("%d%d", &b, &c); 90 tree.update(1, b, b+c-1, 1); 91 } 92 } 93 return 0; 94 }
B题 Little Girl and Problem on Trees
一道CF原题,还是可以用线段树做,由于题目所给的树的特殊性,可以把树上的链条拆开,单独处理树的根节点,这样就变成最基本的简单线段树了,这道题过的人最少
参考代码
1 #include <iostream> 2 #include <cstring> 3 #include <cstdio> 4 #include <vector> 5 6 using namespace std; 7 8 const int N=100006; 9 typedef long long LL; 10 11 struct Interval_Tree 12 { 13 struct node 14 { 15 int s, t; 16 LL val, lazy; 17 void init(int a, int b) 18 { 19 s=a, t=b, val=0ll, lazy=0ll; 20 } 21 } T[N<<2]; 22 23 void build(int id, int L, int R) 24 { 25 T[id].init(L, R); 26 if(L==R) return; 27 int mid=(L+R)>>1; 28 build(id<<1, L, mid), build(id<<1|1, mid+1, R); 29 } 30 31 inline void pushDown(int id) 32 { 33 T[id<<1].lazy+=T[id].lazy; 34 T[id<<1|1].lazy+=T[id].lazy; 35 T[id<<1].val+=(T[id<<1].t-T[id<<1].s+1)*T[id].lazy; 36 T[id<<1|1].val+=(T[id<<1|1].t-T[id<<1|1].s+1)*T[id].lazy; 37 T[id].lazy=0ll; 38 } 39 40 void update(int id, int L, int R, LL val) 41 { 42 if(L<=T[id].s && T[id].t<=R) 43 { 44 T[id].lazy+=val; 45 T[id].val+=(T[id].t-T[id].s+1)*val; 46 return; 47 } 48 int mid=(T[id].s+T[id].t)>>1; 49 if(T[id].lazy!=0) pushDown(id); 50 if(R<=mid) update(id<<1, L, R, val); 51 else if(L>mid) update(id<<1|1, L, R, val); 52 else update(id<<1, L, R, val), update(id<<1|1, L, R, val); 53 T[id].val=T[id<<1].val+T[id<<1|1].val; 54 } 55 56 LL query(int id, int pos) 57 { 58 if(T[id].s==T[id].t) return T[id].val; 59 int mid=(T[id].s+T[id].t)>>1; 60 if(T[id].lazy!=0) pushDown(id); 61 if(pos<=mid) return query(id<<1, pos); 62 else return query(id<<1|1, pos); 63 } 64 } tree; 65 66 int s[N], t[N], label[N], de[N], belong[N]; 67 int n, q, root, cnt; 68 vector <int> arc[N]; 69 70 void DFS(int u, int pre, int cur) 71 { 72 label[u]=++cnt, belong[u]=cur; 73 int len=(int)arc[u].size(); 74 bool flag=true; 75 for(int i=0; i<len; i++) 76 { 77 int v=arc[u][i]; 78 if(v==pre) continue; 79 flag=false; 80 DFS(v, u, cur); 81 } 82 if(flag) t[cur]=label[u]; 83 } 84 85 int main() 86 { 87 while(scanf("%d%d", &n, &q)!=EOF) 88 { 89 for(int i=1; i<=n; i++) 90 arc[i].clear(), de[i]=0, t[i]=-1; 91 root=-1; 92 for(int i=1, a, b; i<n; i++) 93 { 94 scanf("%d%d", &a, &b); 95 arc[a].push_back(b); 96 arc[b].push_back(a); 97 de[a]++, de[b]++; 98 if(root==-1 && de[a]==1) root=a; 99 if(root==-1 && de[b]==1) root=b; 100 if((root==-1 || de[root]==1) && de[a]>2) root=a; 101 if((root==-1 || de[root]==1) && de[b]>2) root=b; 102 } 103 cnt=0; 104 int len=(int)arc[root].size(); 105 for(int i=0; i<len; i++) 106 { 107 s[i+1]=cnt+1; 108 DFS(arc[root][i], root, i+1); 109 } 110 label[root]=++cnt; 111 tree.build(1, 1, cnt); 112 for(int i=0, flag, v, x, d; i<q; i++) 113 { 114 scanf("%d", &flag); 115 if(flag==0) 116 { 117 scanf("%d%d%d", &v, &x, &d); 118 if(v==root) 119 { 120 tree.update(1, label[root], label[root], x); 121 if(x<=0) continue; 122 for(int j=1; j<=len; j++) 123 tree.update(1, s[j], min(t[j], s[j]+d-1), x); 124 } 125 else 126 { 127 tree.update(1, label[v], min(label[v]+d, t[belong[v]]), x); 128 tree.update(1, max(s[belong[v]], label[v]-d), label[v], x); 129 tree.update(1, label[v], label[v], -x); 130 if(d<=label[v]-s[belong[v]]) continue; 131 tree.update(1, label[root], label[root], x); 132 d-=label[v]-s[belong[v]]+1; 133 if(d==0) continue; 134 for(int j=1; j<=len; j++) 135 { 136 if(j==belong[v]) continue; 137 tree.update(1, s[j], min(s[j]+d-1, t[j]), x); 138 } 139 } 140 continue; 141 } 142 scanf("%d", &v); 143 printf("%lld\n", tree.query(1, label[v])); 144 } 145 } 146 return 0; 147 }
经典双端队列题目,做法不再累述
参考代码
1 #include <cstdio> 2 #include <cstring> 3 #include <iostream> 4 5 using namespace std; 6 7 const int N=1000006; 8 9 int Q[N], data[N], Min[N], Max[N]; 10 int n, k, head, tail; 11 12 void deal_min() 13 { 14 head=tail=0; 15 for(int i=0; i<k; i++) 16 { 17 while(head!=tail && data[Q[tail-1]]>=data[i]) tail--; 18 Q[tail++]=i; 19 } 20 Min[0]=data[Q[head]]; 21 for(int i=k; i<n; i++) 22 { 23 while(head!=tail && data[Q[tail-1]]>=data[i]) tail--; 24 Q[tail++]=i; 25 while(head!=tail && Q[head]<i-k+1) head++; 26 Min[i-k+1]=data[Q[head]]; 27 } 28 } 29 30 void deal_max() 31 { 32 head=tail=0; 33 for(int i=0; i<k; i++) 34 { 35 while(head!=tail && data[Q[tail-1]]<=data[i]) tail--; 36 Q[tail++]=i; 37 } 38 Max[0]=data[Q[head]]; 39 for(int i=k; i<n; i++) 40 { 41 while(head!=tail && data[Q[tail-1]]<=data[i]) tail--; 42 Q[tail++]=i; 43 while(head!=tail && Q[head]<i-k+1) head++; 44 Max[i-k+1]=data[Q[head]]; 45 } 46 } 47 int main() 48 { 49 scanf("%d%d", &n, &k); 50 for(int i=0; i<n; i++) scanf("%d", data+i); 51 deal_min(); 52 deal_max(); 53 for(int i=0; i<=n-k; i++) 54 { 55 printf("%d", Min[i]); 56 if(i==n-k) printf("\n"); 57 else printf(" "); 58 } 59 for(int i=0; i<=n-k; i++) 60 { 61 printf("%d", Max[i]); 62 if(i==n-k) printf("\n"); 63 else printf(" "); 64 } 65 return 0; 66 }
D题 Picture
扫描线求矩形周长并
我贴的别人的模板
参考代码
1 #include <iostream> 2 #include <stdio.h> 3 #include <string.h> 4 #include <algorithm> 5 #define N 10003 6 #define lson l,m,k<<1 7 #define rson m,r,k<<1|1 8 using namespace std; 9 struct segment 10 { 11 int len,cover; 12 }; 13 struct line1 14 { 15 int x,y1,y2; 16 int flag; 17 bool operator<(const line1 &L) const 18 { 19 if(x==L.x) return flag>L.flag; 20 return x<L.x; 21 } 22 }; 23 struct line2 24 { 25 int y,x1,x2; 26 int flag; 27 bool operator<(const line2 &L) const 28 { 29 if(y==L.y) return flag>L.flag; 30 return y<L.y; 31 } 32 }; 33 segment st[N<<2]; 34 line1 L1[N]; 35 line2 L2[N]; 36 int rcx[N],rcy[N]; 37 void up1(int &k,int &l,int &r) 38 { 39 if(st[k].cover) 40 st[k].len=rcy[r]-rcy[l]; 41 else if(l+1==r) 42 st[k].len=0; 43 else 44 st[k].len=st[k<<1].len+st[k<<1|1].len; 45 } 46 void up2(int &k,int &l,int &r) 47 { 48 if(st[k].cover) 49 st[k].len=rcx[r]-rcx[l]; 50 else if(l+1==r) 51 st[k].len=0; 52 else 53 st[k].len=st[k<<1].len+st[k<<1|1].len; 54 } 55 void build(int l,int r,int k) 56 { 57 st[k].cover=st[k].len=0; 58 if(l+1==r) 59 return ; 60 int m=(l+r)>>1; 61 build(lson); 62 build(rson); 63 } 64 int flag; 65 void update1(int &y1,int &y2,int l,int r,int k) 66 { 67 if(y1<=rcy[l]&&rcy[r]<=y2) 68 { 69 st[k].cover+=flag; 70 up1(k,l,r); 71 return ; 72 } 73 int m=(l+r)>>1; 74 if(y1<rcy[m]) update1(y1,y2,lson); 75 if(y2>rcy[m]) update1(y1,y2,rson); 76 up1(k,l,r); 77 } 78 void update2(int &x1,int &x2,int l,int r,int k) 79 { 80 if(x1<=rcx[l]&&rcx[r]<=x2) 81 { 82 st[k].cover+=flag; 83 up2(k,l,r); 84 return ; 85 } 86 int m=(l+r)>>1; 87 if(x1<rcx[m]) update2(x1,x2,lson); 88 if(x2>rcx[m]) update2(x1,x2,rson); 89 up2(k,l,r); 90 } 91 int main() 92 { 93 int n,nl,pl,len; 94 int i,j,k; 95 int x1,x2,y1,y2; 96 while(scanf("%d",&n)!=EOF) 97 { 98 for(j=i=0; i<n; i++) 99 { 100 scanf("%d%d%d%d",&x1,&y1,&x2,&y2); 101 L1[j].x=x1; 102 L1[j].y1=y1; 103 L1[j].y2=y2; 104 L2[j].y=y1; 105 L2[j].x1=x1; 106 L2[j].x2=x2; 107 L1[j].flag=L2[j].flag=1; 108 rcx[j]=x1; 109 rcy[j]=y1; 110 j++; 111 112 rcx[j]=x2; 113 rcy[j]=y2; 114 L1[j].x=x2; 115 L1[j].y1=y1; 116 L1[j].y2=y2; 117 L2[j].y=y2; 118 L2[j].x1=x1; 119 L2[j].x2=x2; 120 L1[j].flag=L2[j].flag=-1; 121 j++; 122 } 123 sort(L1,L1+j); 124 sort(rcy,rcy+j); 125 for(k=0,i=1; i<j; i++) 126 if(rcy[i]!=rcy[k]) 127 rcy[++k]=rcy[i]; 128 build(0,k,1); 129 len=0; 130 for(i=0; i<j; i++) 131 { 132 pl=st[1].len; 133 flag=L1[i].flag; 134 update1(L1[i].y1,L1[i].y2,0,k,1); 135 nl=st[1].len; 136 len+=pl>nl?pl-nl:nl-pl; 137 } 138 sort(L2,L2+j); 139 sort(rcx,rcx+j); 140 for(k=0,i=1; i<j; i++) 141 if(rcx[i]!=rcx[k]) 142 rcx[++k]=rcx[i]; 143 build(0,k,1); 144 for(i=0; i<j; i++) 145 { 146 pl=st[1].len; 147 flag=L2[i].flag; 148 update2(L2[i].x1,L2[i].x2,0,k,1); 149 nl=st[1].len; 150 len+=pl>nl?pl-nl:nl-pl; 151 } 152 printf("%d\n",len); 153 } 154 return 0; 155 }
E题 How Many Buildings
维护一个单调栈,注意高度为 0 的情况不能入栈,我在这里WA了好几发
参考代码
1 #include <iostream> 2 #include <cstring> 3 #include <cstdio> 4 #include <stack> 5 6 using namespace std; 7 8 stack <int> s; 9 10 int main() 11 { 12 int cnt=0, n, a; 13 while(scanf("%d", &n)!=EOF) 14 { 15 int ans=0; 16 while(!s.empty()) s.pop(); 17 for(int i=0; i<n; i++) 18 { 19 scanf("%d", &a); 20 while(!s.empty() && s.top()>a) 21 { 22 ans++; 23 s.pop(); 24 } 25 if(!s.empty() && s.top()<a || s.empty() && a!=0) s.push(a); 26 } 27 while(!s.empty()) s.pop(), ans++; 28 printf("Case %d: %d\n", ++cnt, ans); 29 } 30 return 0; 31 }
F题 Cookies Test
维护一个大根堆和小根堆,简单的模拟下
参考代码
1 #include <queue> 2 #include <iostream> 3 #include <vector> 4 #include <cstdio> 5 #include <cstring> 6 7 using namespace std; 8 9 char s[20]; 10 priority_queue <int, vector<int>, less<int> > Min; 11 priority_queue <int, vector<int>, greater<int> > Max; 12 13 int get() 14 { 15 int sum=0; 16 if(s[0]=='#') return -1; 17 for(int i=0; s[i]; i++) sum=sum*10+s[i]-'0'; 18 return sum; 19 } 20 21 void rebuild() 22 { 23 while(Min.size()<Max.size()) 24 { 25 Min.push(Max.top()); 26 Max.pop(); 27 } 28 while(Min.size()>Max.size()) 29 { 30 Max.push(Min.top()); 31 Min.pop(); 32 } 33 } 34 35 int main() 36 { 37 while(!Min.empty()) Min.pop(); 38 while(!Max.empty()) Max.pop(); 39 while(scanf("%s", s)!=EOF) 40 { 41 int val=get(); 42 if(val==-1) 43 { 44 printf("%d\n", Max.top()); 45 Max.pop(); 46 rebuild(); 47 continue; 48 } 49 if(Min.empty() || Max.top()>=val) Min.push(val); 50 else if(val>Max.top()) Max.push(val); 51 rebuild(); 52 } 53 return 0; 54 }
G题 Bracket Sequence
线段树好题!把左括号转换成 -1,右括号转换成为 1
一段区间的括号序列是合法的,当且仅当这段区间的和是 0 且部分和的最大值小于等于 0,我把所有的操作分开写了,导致线段树的操作有点多
参考代码
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 5 using namespace std; 6 7 const int N=100006; 8 char buff[N]; 9 10 struct Interval_Tree 11 { 12 struct node 13 { 14 int s, t, sum, Max, Min, Set, Rev; 15 inline void init(int L, int R) 16 { 17 s=L, t=R, sum=Max=Min=(buff[L]=='('?-1:1), Set=Rev=0; 18 } 19 } T[N<<2]; 20 21 inline void pushUp(int id) 22 { 23 T[id].sum=T[id<<1].sum+T[id<<1|1].sum; 24 T[id].Max=max(T[id<<1].Max, T[id<<1].sum+T[id<<1|1].Max); 25 T[id].Min=min(T[id<<1].Min, T[id<<1].sum+T[id<<1|1].Min); 26 } 27 28 inline void Set_all(int id, int val) 29 { 30 T[id].Set=val, T[id].Rev=0, T[id].sum=(T[id].t-T[id].s+1)*val; 31 T[id].Min=min(val, T[id].sum), T[id].Max=max(val, T[id].sum); 32 } 33 34 inline void Rev_all(int id) 35 { 36 T[id].Rev^=1, T[id].sum=-T[id].sum; 37 swap(T[id].Min, T[id].Max); 38 T[id].Min=-T[id].Min, T[id].Max=-T[id].Max; 39 } 40 41 inline void pushDown(int id) 42 { 43 if(T[id].Set) 44 { 45 Set_all(id<<1, T[id].Set), Set_all(id<<1|1, T[id].Set); 46 T[id].Set=0; 47 } 48 if(T[id].Rev) 49 { 50 Rev_all(id<<1), Rev_all(id<<1|1); 51 T[id].Rev=0; 52 } 53 } 54 55 void build(int id, int L, int R) 56 { 57 T[id].init(L, R); 58 if(L==R) return; 59 int mid=(L+R)>>1; 60 build(id<<1, L, mid), build(id<<1|1, mid+1, R); 61 pushUp(id); 62 } 63 64 void Set(int id, int L, int R, int val) 65 { 66 if(L<=T[id].s && T[id].t<=R) 67 { 68 Set_all(id, val); 69 return; 70 } 71 pushDown(id); 72 int mid=(T[id].s+T[id].t)>>1; 73 if(R<=mid) Set(id<<1, L, R, val); 74 else if(L>mid) Set(id<<1|1, L, R, val); 75 else Set(id<<1, L, R, val), Set(id<<1|1, L, R, val); 76 pushUp(id); 77 } 78 79 void Rev(int id, int L, int R) 80 { 81 if(L<=T[id].s && T[id].t<=R) 82 { 83 Rev_all(id); 84 return; 85 } 86 pushDown(id); 87 int mid=(T[id].s+T[id].t)>>1; 88 if(R<=mid) Rev(id<<1, L, R); 89 else if(L>mid) Rev(id<<1|1, L, R); 90 else Rev(id<<1, L, R), Rev(id<<1|1, L, R); 91 pushUp(id); 92 } 93 94 void query(int id, int L, int R, int &Max, int &sum) 95 { 96 if(L<=T[id].s && T[id].t<=R) 97 { 98 Max=T[id].Max; 99 sum=T[id].sum; 100 return; 101 } 102 pushDown(id); 103 int mid=(T[id].s+T[id].t)>>1; 104 if(R<=mid) query(id<<1, L, R, Max, sum); 105 else if(L>mid) query(id<<1|1, L, R, Max, sum); 106 else 107 { 108 int LMax, Lsum, RMax, Rsum; 109 query(id<<1, L, R, LMax, Lsum); 110 query(id<<1|1, L, R, RMax, Rsum); 111 Max=max(LMax, Lsum+RMax); 112 sum=Lsum+Rsum; 113 } 114 pushUp(id); 115 } 116 } tree; 117 118 int t, n, m; 119 120 int main() 121 { 122 scanf("%d", &t); 123 for(int ca=1; ca<=t; ca++) 124 { 125 scanf("%d%s", &n, buff); 126 tree.build(1, 0, n-1); 127 printf("Case %d:\n", ca); 128 scanf("%d", &m); 129 for(int i=0; i<m; i++) 130 { 131 scanf("%s", buff); 132 if(buff[0]=='q') 133 { 134 int sum, Max, L, R; 135 scanf("%d%d", &L, &R); 136 tree.query(1, L, R, Max, sum); 137 if(Max<=0 && sum==0) printf("YES\n"); 138 else printf("NO\n"); 139 } 140 if(buff[0]=='s') 141 { 142 char s[2]; 143 int L, R; 144 scanf("%d%d%s", &L, &R, s); 145 tree.Set(1, L, R, s[0]=='('?-1:1); 146 } 147 if(buff[0]=='r') 148 { 149 int L, R; 150 scanf("%d%d", &L, &R); 151 tree.Rev(1, L, R); 152 } 153 } 154 printf("\n"); 155 } 156 return 0; 157 }
H题 论程序的阿卡林化
由于题目的特殊性:k不变,马上联想到用双端队列来做
参考代码
1 #include <iostream> 2 #include <cstring> 3 #include <cstdio> 4 #include <stack> 5 6 using namespace std; 7 8 const int N=200006; 9 10 int n, m, k, head, tail, Q[N], flag, len; 11 char name[N][5], s[100]; 12 stack <int> ans; 13 14 void Pop() 15 { 16 if(flag==0) 17 { 18 ans.push(Q[(tail-1+N)%N]); 19 tail=(tail-1+N)%N; 20 } 21 else 22 { 23 ans.push(Q[head]); 24 head=(head+1)%N; 25 } 26 len--; 27 } 28 29 void Push() 30 { 31 if(flag==0) 32 { 33 Q[(head-1+N)%N]=n; 34 head=(head-1+N)%N; 35 } 36 else 37 { 38 Q[tail]=n; 39 tail=(tail+1)%N; 40 } 41 n++, len++; 42 while(len>k) Pop(); 43 } 44 45 int main() 46 { 47 int cnt=0; 48 while(scanf("%d%d%d", &n, &m, &k)!=EOF) 49 { 50 for(int i=0; i<n; i++) scanf("%s", name[i]); 51 while(!ans.empty()) ans.pop(); 52 head=tail=flag=len=0; 53 for(int i=0; i<min(k, n); i++) Q[tail++]=i, len++; 54 for(int i=n-1; i>=k; i--) ans.push(i); 55 for(int i=0; i<m; i++) 56 { 57 scanf("%s", s); 58 if(s[0]=='A') 59 { 60 for(int j=4; s[j]; j++) 61 { 62 name[n][j-4]=s[j]; 63 if(s[j]==')') 64 { 65 name[n][j-4]=0; 66 break; 67 } 68 } 69 Push(); 70 } 71 else flag^=1; 72 } 73 while(len>0) Pop(); 74 if(cnt!=0) printf("\n"); 75 while(!ans.empty()) 76 { 77 printf("%s\n", name[ans.top()]); 78 ans.pop(); 79 } 80 cnt++; 81 } 82 return 0; 83 }
I题 A Simple Problem with Integers
线段树僵尸级别的陈题,如果要练习懒操作的话,这是一道很基本的入门题,如果要练习树状数组的话,这是最高级版本的树状数组题目
参考代码
1 #include <iostream> 2 #include <cstring> 3 #include <cstdio> 4 #include <algorithm> 5 6 using namespace std; 7 8 typedef long long LL; 9 const int N=100006; 10 11 LL data[N]; 12 int n, m; 13 14 struct Interval_Tree 15 { 16 struct node 17 { 18 int s, t; 19 LL sum, lazy; 20 void init(int a, int b, LL c) 21 { 22 s=a, t=b, sum=c, lazy=0; 23 } 24 } T[N<<2]; 25 26 void build(int id, int L, int R) 27 { 28 T[id].init(L, R, data[L]); 29 if(L==R) return; 30 int mid=(L+R)>>1; 31 build(id<<1, L, mid), build(id<<1|1, mid+1, R); 32 T[id].sum=T[id<<1].sum+T[id<<1|1].sum; 33 } 34 35 void pushDown(int id) 36 { 37 T[id<<1].lazy+=T[id].lazy; 38 T[id<<1|1].lazy+=T[id].lazy; 39 T[id<<1].sum+=(T[id<<1].t-T[id<<1].s+1)*T[id].lazy; 40 T[id<<1|1].sum+=(T[id<<1|1].t-T[id<<1|1].s+1)*T[id].lazy; 41 T[id].lazy=0; 42 } 43 44 void update(int id, int L, int R, LL val) 45 { 46 if(L<=T[id].s && T[id].t<=R) 47 { 48 T[id].lazy+=val; 49 T[id].sum+=(T[id].t-T[id].s+1)*val; 50 return; 51 } 52 int mid=(T[id].s+T[id].t)>>1; 53 if(T[id].lazy!=0) pushDown(id); 54 if(R<=mid) update(id<<1, L, R, val); 55 else if(L>mid) update(id<<1|1, L, R, val); 56 else update(id<<1, L, R, val), update(id<<1|1, L, R, val); 57 T[id].sum=T[id<<1].sum+T[id<<1|1].sum; 58 } 59 60 LL query(int id, int L, int R) 61 { 62 if(L<=T[id].s && T[id].t<=R) return T[id].sum; 63 if(T[id].lazy!=0) pushDown(id); 64 int mid=(T[id].s+T[id].t)>>1; 65 if(R<=mid) return query(id<<1, L, R); 66 else if(L>mid) return query(id<<1|1, L, R); 67 else return query(id<<1, L, R)+query(id<<1|1, L, R); 68 } 69 } tree; 70 71 char s[2]; 72 73 int main() 74 { 75 scanf("%d%d", &n, &m); 76 for(int i=1; i<=n; i++) scanf("%lld", &data[i]); 77 tree.build(1, 1, n); 78 for(int i=0, a, b, c; i<m; i++) 79 { 80 scanf("%s", s); 81 if(s[0]=='Q') 82 { 83 scanf("%d%d", &a, &b); 84 printf("%lld\n", tree.query(1, a, b)); 85 } 86 else 87 { 88 scanf("%d%d%d", &a, &b, &c); 89 tree.update(1, a, b, c); 90 } 91 } 92 return 0; 93 }
J题 Never Wait for Weights
简单并查集,我的做法是先把所有的数据读入,建好图,根据关系,先求出两个之间的重量差,离线的处理,边处理边合并
参考代码
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 5 using namespace std; 6 7 const int N=100006; 8 9 struct data 10 { 11 int u, val, next; 12 void init(int a, int b, int c) 13 { 14 u=a, val=b, next=c; 15 } 16 } edge[N<<1]; 17 int head[N], tot, num, n, m; 18 int weight[N], fa[N]; 19 char s[6]; 20 21 struct node 22 { 23 bool flag; 24 int a, b; 25 } query[N]; 26 27 void add_edge(int s, int t, int val) 28 { 29 edge[tot].init(t, val, head[s]); 30 head[s]=tot++; 31 } 32 33 void DFS(int u, int pre) 34 { 35 for(int e=head[u]; e!=-1; e=edge[e].next) 36 { 37 int v=edge[e].u, val=edge[e].val; 38 if(v==pre || weight[v]!=0x3fffffff) continue; 39 weight[v]=weight[u]+val; 40 DFS(v, u); 41 } 42 } 43 44 int find_set(int x) 45 { 46 if(x!=fa[x]) fa[x]=find_set(fa[x]); 47 return fa[x]; 48 } 49 50 int main() 51 { 52 while(scanf("%d%d", &n, &m), n!=0 || m!=0) 53 { 54 tot=num=0; 55 memset(head, -1, sizeof head); 56 for(int i=0, a, b, c; i<m; i++) 57 { 58 scanf("%s", s); 59 if(s[0]=='!') 60 { 61 scanf("%d%d%d", &a, &b, &c); 62 add_edge(a, b, c); 63 add_edge(b, a, -c); 64 query[num].a=a, query[num].b=b; 65 query[num].flag=0; 66 num++; 67 } 68 else 69 { 70 scanf("%d%d", &query[num].a, &query[num].b); 71 query[num].flag=1; 72 num++; 73 } 74 } 75 for(int i=1; i<=n; i++) weight[i]=0x3fffffff; 76 for(int i=1; i<=n; i++) 77 if(weight[i]==0x3fffffff) 78 { 79 weight[i]=0; 80 DFS(i, -1); 81 } 82 for(int i=1; i<=n; i++) fa[i]=i; 83 for(int i=0; i<m; i++) 84 { 85 int f1=find_set(query[i].a); 86 int f2=find_set(query[i].b); 87 if(query[i].flag) 88 { 89 if(f1==f2) printf("%d\n", weight[query[i].b]-weight[query[i].a]); 90 else printf("UNKNOWN\n"); 91 } 92 else 93 { 94 if(f1!=f2) fa[f1]=f2; 95 } 96 } 97 } 98 return 0; 99 }
和 I 题一样的僵尸级别的线段树陈题,区间最大值
参考代码
1 #include <iostream> 2 #include <cstring> 3 #include <cstdio> 4 5 using namespace std; 6 7 typedef long long LL; 8 const int N=1000006; 9 10 LL data[N]; 11 int n, m; 12 13 struct Interval_Tree 14 { 15 struct node 16 { 17 int s, t; 18 LL Max, lazy; 19 void init(int a, int b, LL c) 20 { 21 s=a, t=b, Max=c, lazy=0; 22 } 23 } T[N<<2]; 24 25 void build(int id, int L, int R) 26 { 27 T[id].init(L, R, data[L]); 28 if(L==R) return; 29 int mid=(L+R)>>1; 30 build(id<<1, L, mid), build(id<<1|1, mid+1, R); 31 T[id].Max=max(T[id<<1].Max, T[id<<1|1].Max); 32 } 33 34 void pushDown(int id) 35 { 36 T[id<<1].lazy+=T[id].lazy; 37 T[id<<1|1].lazy+=T[id].lazy; 38 T[id<<1].Max+=T[id].lazy; 39 T[id<<1|1].Max+=T[id].lazy; 40 T[id].lazy=0; 41 } 42 43 void update(int id, int L, int R, LL val) 44 { 45 if(L<=T[id].s && T[id].t<=R) 46 { 47 T[id].Max+=val; 48 T[id].lazy+=val; 49 return; 50 } 51 if(T[id].lazy!=0) pushDown(id); 52 int mid=(T[id].s+T[id].t)>>1; 53 if(R<=mid) update(id<<1, L, R, val); 54 else if(L>mid) update(id<<1|1, L, R, val); 55 else update(id<<1, L, R, val), update(id<<1|1, L, R, val); 56 T[id].Max=max(T[id<<1].Max, T[id<<1|1].Max); 57 } 58 59 LL query(int id, int L, int R) 60 { 61 if(L<=T[id].s && T[id].t<=R) return T[id].Max; 62 if(T[id].lazy) pushDown(id); 63 int mid=(T[id].s+T[id].t)>>1; 64 if(R<=mid) return query(id<<1, L, R); 65 else if(L>mid) return query(id<<1|1, L, R); 66 else return max(query(id<<1, L, R), query(id<<1|1, L, R)); 67 } 68 } tree; 69 70 int main() 71 { 72 scanf("%d", &n); 73 for(int i=1; i<=n; i++) scanf("%lld", data+i); 74 tree.build(1, 1, n); 75 scanf("%d", &m); 76 for(int i=0, a, s, t; i<m; i++) 77 { 78 LL val; 79 scanf("%d", &a); 80 if(a==1) 81 { 82 scanf("%d%d", &s, &t); 83 if(s>t) swap(s, t); 84 if(s<1) s=1; 85 if(t>n) t=n; 86 printf("%lld\n", tree.query(1, s, t)); 87 } 88 else 89 { 90 scanf("%d%d%lld", &s, &t, &val); 91 if(s>t) swap(s, t); 92 if(s<1) s=1; 93 if(t>n) t=n; 94 tree.update(1, s, t, val); 95 } 96 } 97 return 0; 98 }
L题 中二少女与字符串
把所有的字符串的后缀添加进字典树中,然后该怎么做就怎么做了
参考代码
1 #include <iostream> 2 #include <cstring> 3 #include <cstdio> 4 #include <algorithm> 5 6 using namespace std; 7 8 const int N=4000006; 9 10 char buff[2000], s[30]; 11 int Max, t; 12 13 struct Trie 14 { 15 struct node 16 { 17 int next[26], cnt; 18 void init() 19 { 20 for(int i=0; i<26; i++) next[i]=-1; 21 cnt=0; 22 } 23 } trie[N]; 24 int num, ans; 25 26 void Insert(int s) 27 { 28 int u=0; 29 for(int i=s; buff[i]; i++) 30 { 31 int id=buff[i]-'a'; 32 if(trie[u].next[id]==-1) 33 { 34 trie[num].init(); 35 trie[u].next[id]=num++; 36 } 37 u=trie[u].next[id]; 38 } 39 } 40 41 void deal(int u, int res) 42 { 43 if(res>Max) return; 44 if(u!=0) ans++; 45 for(int i=0; i<26; i++) 46 { 47 if(trie[u].next[i]==-1) continue; 48 deal(trie[u].next[i], res+((s[i]-'0')^1)); 49 } 50 } 51 } tree; 52 53 int main() 54 { 55 scanf("%d", &t); 56 while(t--) 57 { 58 scanf("%s%s%d", buff, s, &Max); 59 tree.ans=tree.num=0; 60 tree.trie[tree.num++].init(); 61 for(int i=0; buff[i]; i++) 62 tree.Insert(i); 63 tree.deal(0, 0); 64 printf("%d\n", tree.ans); 65 } 66 return 0; 67 }
M题 Islands
并查集僵尸级别的题目,还是离线处理,不过需要把所有的高度排个序,不然会T
参考代码
1 #include <iostream> 2 #include <cstring> 3 #include <cstdio> 4 #include <algorithm> 5 6 using namespace std; 7 8 const int zl[4][2]={-1, 0, 1, 0, 0, 1, 0, -1}; 9 10 struct node 11 { 12 int x, y, H; 13 bool operator <(const node &temp) const 14 { 15 return H>temp.H; 16 } 17 } h[1000006]; 18 int Z, n, m, T, cur; 19 int water[100006], ans[100006], Map[1006][1006], fa[1000006]; 20 21 inline bool in(int x, int y) 22 { 23 return x>=0 && x<n && y>=0 && y<m; 24 } 25 26 int find_set(int x) 27 { 28 if(x!=fa[x]) fa[x]=find_set(fa[x]); 29 return fa[x]; 30 } 31 32 int main() 33 { 34 scanf("%d", &Z); 35 while(Z--) 36 { 37 scanf("%d%d", &n, &m); 38 for(int i=0; i<n; i++) 39 for(int j=0; j<m; j++) 40 { 41 scanf("%d", &Map[i][j]); 42 h[i*m+j].x=i, h[i*m+j].y=j, h[i*m+j].H=Map[i][j]; 43 fa[i*m+j]=i*m+j; 44 } 45 sort(h, h+n*m); 46 scanf("%d", &T); 47 for(int i=0; i<T; i++) scanf("%d", &water[i]); 48 ans[T]=0, cur=0; 49 for(int i=T-1; i>=0; i--) 50 { 51 ans[i]=ans[i+1]; 52 for(; cur<n*m && h[cur].H>water[i]; cur++) 53 { 54 ans[i]++; 55 for(int k=0; k<4; k++) 56 { 57 int x=h[cur].x+zl[k][0]; 58 int y=h[cur].y+zl[k][1]; 59 if(!in(x, y)) continue; 60 if(Map[x][y]<=water[i]) continue; 61 int u=h[cur].x*m+h[cur].y; 62 int v=x*m+y; 63 int f1=find_set(u); 64 int f2=find_set(v); 65 if(f1!=f2) 66 { 67 ans[i]--; 68 fa[f1]=f2; 69 } 70 } 71 } 72 } 73 for(int i=0; i<T; i++) printf("%d ", ans[i]); 74 printf("\n"); 75 } 76 return 0; 77 }
N题 贪玩的xie
某场 CF 原题,好像是 Div2 的 E
可以先离散化,然后再利用线段树维护地雷的信息,简单但不易想到的公式:res=res1+res2+sum2*cnt1-sum1*cnt2
参考代码
1 #include <iostream> 2 #include <cstdio> 3 #include <algorithm> 4 #include <vector> 5 #include <map> 6 #include <cstring> 7 8 using namespace std; 9 10 const int N=400006; 11 typedef long long LL; 12 13 vector <LL> val; 14 map<LL, int> ihash; 15 map<int, LL> iback; 16 LL x[N], old[N]; 17 int t, n, m; 18 struct data 19 { 20 int flag; 21 LL a, b; 22 } op[N]; 23 24 struct node 25 { 26 int s, t; 27 LL cnt, sum, res; 28 void init(int L, int R) 29 { 30 s=L, t=R, cnt=sum=res=0ll; 31 } 32 } ans; 33 34 struct Interval_Tree 35 { 36 node T[N<<2]; 37 void build(int id, int L, int R) 38 { 39 T[id].init(L, R); 40 if(L==R) return; 41 int mid=(L+R)>>1; 42 build(id<<1, L, mid), build(id<<1|1, mid+1, R); 43 } 44 45 inline void pushUp(node &fa, node &L, node &R) 46 { 47 fa.res=L.res+R.res+R.sum*L.cnt-L.sum*R.cnt; 48 fa.sum=L.sum+R.sum; 49 fa.cnt=L.cnt+R.cnt; 50 } 51 52 void Delete(int id, int pos) 53 { 54 if(T[id].s==T[id].t) 55 { 56 T[id].cnt=T[id].sum=T[id].res=0; 57 return; 58 } 59 int mid=(T[id].s+T[id].t)>>1; 60 if(pos<=mid) Delete(id<<1, pos); 61 else Delete(id<<1|1, pos); 62 pushUp(T[id], T[id<<1], T[id<<1|1]); 63 } 64 65 void Insert(int id, int pos) 66 { 67 if(T[id].s==T[id].t) 68 { 69 T[id].cnt=1, T[id].sum=iback[pos], T[id].res=0; 70 return; 71 } 72 int mid=(T[id].s+T[id].t)>>1; 73 if(pos<=mid) Insert(id<<1, pos); 74 else Insert(id<<1|1, pos); 75 pushUp(T[id], T[id<<1], T[id<<1|1]); 76 } 77 78 node query(int id, int L, int R) 79 { 80 if(L<=T[id].s && T[id].t<=R) return T[id]; 81 int mid=(T[id].s+T[id].t)>>1; 82 if(R<=mid) return query(id<<1, L, R); 83 else if(L>mid) return query(id<<1|1, L, R); 84 node sL=query(id<<1, L, R), sR=query(id<<1|1, L, R), fa; 85 pushUp(fa, sL, sR); 86 return fa; 87 } 88 } tree; 89 90 int main() 91 { 92 scanf("%d", &t); 93 for(int ca=1; ca<=t; ca++) 94 { 95 val.clear(); 96 scanf("%d", &n); 97 old[0]=n; 98 for(int i=1; i<=n; i++) 99 { 100 scanf("%lld", &x[i]); 101 old[i]=x[i]; 102 val.push_back(x[i]); 103 } 104 scanf("%d", &m); 105 for(int i=0; i<m; i++) 106 { 107 scanf("%d%lld%lld", &op[i].flag, &op[i].a, &op[i].b); 108 if(op[i].flag==1) 109 { 110 x[op[i].a]+=op[i].b; 111 val.push_back(x[op[i].a]); 112 } 113 else 114 { 115 val.push_back(op[i].a); 116 val.push_back(op[i].b); 117 } 118 } 119 sort(val.begin(), val.end()); 120 ihash.clear(), iback.clear(), n=0; 121 for(vector<LL>::iterator it=val.begin(); it!=val.end(); it++) 122 { 123 if(ihash.find(*it)!=ihash.end()) continue; 124 ihash.insert(make_pair(*it, ++n)); 125 iback.insert(make_pair(n, *it)); 126 } 127 tree.build(1, 1, n); 128 for(int i=1; i<=old[0]; i++) tree.Insert(1, ihash[old[i]]); 129 for(int i=0; i<m; i++) 130 { 131 if(op[i].flag==1) 132 { 133 tree.Delete(1, ihash[old[op[i].a]]); 134 old[op[i].a]+=op[i].b; 135 tree.Insert(1, ihash[old[op[i].a]]); 136 } 137 else 138 { 139 ans=tree.query(1, ihash[op[i].a], ihash[op[i].b]); 140 printf("%lld\n", ans.res); 141 } 142 } 143 } 144 return 0; 145 }