2017 ACM/ICPC Asia Regional Shenyang Online

不想去听老师读PPT上的公式,来统一更一下网络赛的情况。。。。。

A string string string

后缀数组,连续k个后缀的LCP - max(第一个后缀与上一个后缀的Height,最后一个后缀与下一个后缀的Height)。

  1 #include <cstdio>
  2 #include <cstring>
  3 #include <iostream>
  4 #include <algorithm>
  5 #include <cmath>
  6 #include <map>
  7 #define ws WS
  8 using namespace std;
  9 const int MAXN=2e5+50;
 10 int n,k;
 11 int Sa[MAXN];
 12 int Rank[MAXN];
 13 int Heigh[MAXN];
 14 int wa[MAXN],wb[MAXN],wv[MAXN],ws[MAXN];
 15 int cmp(int *r,int a,int b,int l){
 16     return r[a]==r[b]&&r[a+l]==r[b+l];
 17 }
 18 void get_sa(char *r,int *Sa,int n,int m){
 19     int i,j,p,*x=wa,*y=wb,*t;
 20     for(i=0;i<m;i++)
 21         ws[i]=0;
 22     for(i=0;i<n;i++)
 23         ws[x[i]=r[i]]++;
 24     for(i=1;i<m;i++)
 25         ws[i]+=ws[i-1];
 26     for(i=n-1;i>=0;i--)
 27         Sa[--ws[x[i]]]=i;
 28     for(j=1,p=1;p<n;j*=2,m=p){
 29         for(p=0,i=n-j;i<n;i++)
 30             y[p++]=i;
 31         for(i=0;i<n;i++)
 32             if(Sa[i]>=j)
 33                 y[p++]=Sa[i]-j;
 34         for(i=0;i<n;i++)
 35             wv[i]=x[y[i]];
 36         for(i=0;i<m;i++)
 37             ws[i]=0;
 38         for(i=0;i<n;i++)
 39             ws[wv[i]]++;
 40         for(i=1;i<m;i++)
 41             ws[i]+=ws[i-1];
 42         for(i=n-1;i>=0;i--)
 43             Sa[--ws[wv[i]]]=y[i];
 44         for(t=x,x=y,y=t,p=1,x[Sa[0]]=0,i=1;i<n;i++)
 45             x[Sa[i]]=cmp(y,Sa[i-1],Sa[i],j)?p-1:p++;
 46     }
 47 }
 48 void get_heigh(char *s,int n){
 49     int k=0;
 50     for(int i=1;i<=n;i++) Rank[Sa[i]]=i;
 51     for(int i=0;i<n;i++)
 52     {
 53         if(k)k--;
 54         int j=Sa[Rank[i]-1];
 55         while(s[i+k]==s[j+k]) k++;
 56         Heigh[Rank[i]]=k;
 57     }
 58 }
 59 int dp[MAXN][35];
 60 void ST(){
 61     int tmp=(int)(log((double)n)/log(2.0));
 62     for(int j=1;j<=tmp;j++)
 63     for(int i=1;i<=n;i++){
 64         dp[i][j]=0;
 65     }
 66     for(int i=1;i<=n;i++) dp[i][0]=Heigh[i];
 67     for(int j=1;j<=tmp;j++)
 68     for(int i=1;i<=n;i++){
 69         dp[i][j]=min(dp[i][j-1],dp[i+(1<<(j-1))][j-1]);
 70     }
 71 }
 72 int LCP(int L,int H){
 73     int k=(int)(log((double)H-L+1)/log(2.0));
 74     return min(dp[L][k],dp[H-(1<<k)+1][k]);
 75 }
 76 
 77 char s[MAXN];
 78 int main(){
 79     int t;
 80     scanf("%d",&t);
 81     while(t--){
 82         scanf("%d",&k);
 83         scanf("%s",s);
 84         n=strlen(s);
 85         get_sa(s,Sa,n+1,150);
 86         get_heigh(s,n);
 87         Heigh[n+1]=0;
 88         ST();
 89         if(k==1){
 90             long long ans=0;
 91             for(int i=1;i<=n;i++){
 92                 ans+=Sa[i]+1-max(Heigh[i],Heigh[i+1]);
 93             }
 94             printf("%lld
",ans);
 95             continue;
 96         }
 97         long long ans=0;
 98         for(int i=1;i<=n-k+1;i++){
 99             int tmp=LCP(i+1,i+k-1);
100             ans+=max(0,tmp-max(Heigh[i],Heigh[i+k]));
101         }
102         printf("%lld
",ans);
103     }
104 
105     return 0;
106 }
Psong

B cable cable cable

保证每个颜色至少出现在(m-k+1)个屏幕上即可。

C happy happy happy

unsolved

D array array array

分别最长不下降子序列和最长不上升子序列

F number number number

矩阵快速幂 f[2*n+3]-1

F gems gems gems

最长的步伐不超过sqrt(n),所以dp[i][j]代表走到第i个位置当前步伐为j,因为最后结束情况很多,所以倒过来做,最后答案就是dp[1][1]。

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 
 4 const int MAXN=2e4+5;
 5 
 6 int n;
 7 int a[MAXN];
 8 int sum[MAXN];
 9 int dp[MAXN][205];
10 
11 int main(){
12     int t;
13     scanf("%d",&t);
14     while(t--){
15         scanf("%d",&n);
16         for(int i=1;i<=n;i++){
17             scanf("%d",&a[i]);
18             sum[i]=sum[i-1]+a[i];
19         }
20         memset(dp,0,sizeof(dp));
21         for(int i=n;i>=1;i--)
22         for(int k=1;k*(k+1)/2<=n;k++){
23             if(i+k-1<=n){
24                 dp[i][k]=sum[i+k-1]-sum[i-1]-dp[i+k][k];
25             }
26             if(i+k<=n){
27                 dp[i][k]=max(dp[i][k],sum[i+k]-sum[i-1]-dp[i+k+1][k+1]);
28             }
29         }
30         printf("%d
",dp[1][1]);
31     }
32 
33     return 0;
34 }
Psong

G mustedge mustedge mustedge

一开始写了个nlognlogn的居然忘了树剖加线段树有两个log,T到死,最后还是刚过去了。

1.双连通缩点,然后树剖修改权值。树上边权一开始为1,每次添加操作为将路径上的边权修改为0,查询操作则是查询路径上的和。

  1 #include <bits/stdc++.h>
  2 using namespace std;
  3 
  4 const int MAXN=1e5+5;
  5 
  6 int n,m;
  7 struct Edge{
  8     int to,Next;
  9 }edge[MAXN*2];
 10 int tot;
 11 int head[MAXN];
 12 inline void init(int tt){
 13     tot=0;
 14     for(int i=0;i<=tt;i++) head[i]=-1;
 15 }
 16 inline void addedge(int u,int v){
 17     edge[tot].to=v;
 18     edge[tot].Next=head[u];
 19     head[u]=tot++;
 20 }
 21 int top;
 22 int block;
 23 int index;
 24 int dfn[MAXN];
 25 int low[MAXN];
 26 int Stack[MAXN];
 27 int belong[MAXN];
 28 int instack[MAXN];
 29 void tarjan(int u,int fa){
 30     int v;
 31     low[u]=dfn[u]=++index;
 32     Stack[top++]=u;
 33     instack[u]=1;
 34     for(int i=head[u];i!=-1;i=edge[i].Next){
 35         v=edge[i].to;
 36         if(v==fa) continue;
 37         if(!dfn[v]){
 38             tarjan(v,u);
 39             low[u]=min(low[u],low[v]);
 40         }
 41         else if(instack[v]){
 42             low[u]=min(low[u],dfn[v]);
 43         }
 44     }
 45     if(low[u]==dfn[u]){
 46         block++;
 47         while(1){
 48             v=Stack[--top];
 49             instack[v]=0;
 50             belong[v]=block;
 51             if(u==v) break;
 52         }
 53     }
 54 }
 55 void solve(int tt){
 56     for(int i=0;i<=tt;i++)
 57         dfn[i]=instack[i]=0;
 58     index=top=block=0;
 59     tarjan(1,0);
 60 }
 61 
 62 Edge e[MAXN*2];
 63 int cnt;
 64 int first[MAXN];
 65 int deep[MAXN];
 66 int Top[MAXN];
 67 int son[MAXN];
 68 int num[MAXN];
 69 int fa[MAXN];
 70 int p[MAXN];
 71 int pos;
 72 inline void pre(int tt){
 73     pos=1;
 74     cnt=0;
 75     for(int i=0;i<=tt;i++)
 76         son[i]=first[i]=-1;
 77 }
 78 void addedge_new(int u,int v){
 79     e[cnt].to=v;
 80     e[cnt].Next=first[u];
 81     first[u]=cnt++;
 82 }
 83 void dfs1(int u,int par,int d){
 84     deep[u]=d;
 85     fa[u]=par;
 86     num[u]=1;
 87     for(int i=first[u];i!=-1;i=e[i].Next){
 88         int v=e[i].to;
 89         if(v==par) continue;
 90         dfs1(v,u,d+1);
 91         num[u]+=num[v];
 92         if(son[u]==-1||num[v]>num[son[u]])
 93             son[u]=v;
 94     }
 95 }
 96 void dfs2(int u,int sp){
 97     Top[u]=sp;
 98     p[u]=pos++;
 99     if(son[u]==-1) return;
100     dfs2(son[u],sp);
101     for(int i=first[u];i!=-1;i=e[i].Next){
102         int v=e[i].to;
103         if(v!=son[u] && v!=fa[u])
104             dfs2(v,v);
105     }
106 }
107 
108 #define lson (id*2)
109 #define rson (id*2+1)
110 #define mid ((l+r)/2)
111 int lazy[MAXN*4],tre[MAXN*4];
112 inline void push_up(int id){
113     tre[id]=tre[lson]+tre[rson];
114 }
115 inline void build(int id,int l,int r){
116     lazy[id]=0;
117     if(l==r){
118         if(l==1) tre[id]=0;
119         else tre[id]=1;
120         return;
121     }
122     build(lson,l,mid);
123     build(rson,mid+1,r);
124     push_up(id);
125 }
126 inline void push_down(int id){
127     lazy[lson]=lazy[rson]=1;
128     tre[lson]=tre[rson]=0;
129     lazy[id]=0;
130 }
131 inline void update(int id,int l,int r,int ql,int qr){
132     if(ql<=l&&r<=qr){
133         tre[id]=0;
134         lazy[id]=1;
135         return;
136     }
137     if(lazy[id]) push_down(id);
138     if(ql<=mid)
139         update(lson,l,mid,ql,qr);
140     if(mid+1<=qr)
141         update(rson,mid+1,r,ql,qr);
142     push_up(id);
143 }
144 inline int query(int id,int l,int r,int ql,int qr){
145     if(ql<=l&&r<=qr) return tre[id];
146     if(lazy[id]) push_down(id);
147     int res=0;
148     if(ql<=mid)
149         res+=query(lson,l,mid,ql,qr);
150     if(mid+1<=qr)
151         res+=query(rson,mid+1,r,ql,qr);
152     return res;
153 }
154 
155 inline void build_tree(){
156     pre(block);
157     for(int u=1;u<=n;u++){
158         for(int i=head[u];i!=-1;i=edge[i].Next){
159             int v=edge[i].to;
160             if(belong[u]==belong[v]) continue;
161             addedge_new(belong[u],belong[v]);
162         }
163     }
164     dfs1(1,0,1);
165     dfs2(1,1);
166     build(1,1,block);
167 }
168 
169 inline void change(int u,int v){
170     int f1=Top[u],f2=Top[v];
171     while(f1!=f2){
172         if(deep[f1]<deep[f2]){
173             swap(f1,f2);
174             swap(u,v);
175         }
176         update(1,1,block,p[f1],p[u]);
177         u=fa[f1]; f1=Top[u];
178     }
179     if(v!=u){
180         if(deep[u]<deep[v]) swap(u,v);
181         update(1,1,block,p[son[v]],p[u]);
182     }
183 }
184 inline int Query(int u,int v){
185     int f1=Top[u],f2=Top[v];
186     int res=0;
187     while(f1!=f2){
188         if(deep[f1]<deep[f2]){
189             swap(f1,f2);
190             swap(u,v);
191         }
192         res+=query(1,1,block,p[f1],p[u]);
193         u=fa[f1]; f1=Top[u];
194     }
195     if(v!=u){
196         if(deep[u]<deep[v]) swap(u,v);
197         res+=query(1,1,block,p[son[v]],p[u]);
198     }
199     return res;
200 }
201 inline void fun(){
202     int q;
203     scanf("%d",&q);
204     while(q--){
205         int op,u,v;
206         scanf("%d%d%d",&op,&u,&v);
207         u=belong[u]; v=belong[v];
208         if(op==1){
209             change(u,v);
210         }
211         else{
212             printf("%d
",Query(u,v));
213         }
214     }
215 }
216 
217 int main(){
218     int t;
219     scanf("%d",&t);
220     int T=t;
221     while(t--){
222         printf("Case #%d:
",T-t);
223         scanf("%d%d",&n,&m);
224         init(n);
225         for(int i=1;i<=m;i++){
226             int u,v;
227             scanf("%d%d",&u,&v);
228             addedge(u,v);
229             addedge(v,u);
230         }
231         solve(n);
232         build_tree();
233         fun();
234     }
235 
236     return 0;
237 }
Psong

2.先跑出一棵树,把剩下的边看作添加操作。每次添加操作,用并查集向上合并,每条边最多只会合并一次,并用树状数组维护从dfs序,每次合并将子树的值减一。查询操作就是sum(in[u])+sum(out[u])-sum(lca)*2。

  1 #include <bits/stdc++.h>
  2 using namespace std;
  3 const int MAX_V=1e5+5;
  4 const int MAX_LOG=19;
  5 
  6 int depth[MAX_V];
  7 
  8 int f[MAX_V];
  9 int find(int x){
 10     return f[x]==x?x:f[x]=find(f[x]);
 11 }
 12 void merge(int x,int y){
 13     f[find(x)]=find(y);
 14 }
 15 void pre(int n){
 16     for(int i=0;i<=n;i++) f[i]=i;
 17 }
 18 
 19 struct Edge{
 20     int to,Next;
 21 } edge[MAX_V*2];
 22 int tot;
 23 int head[MAX_V];
 24 void addedge(int u,int v){
 25     edge[tot].to=v;
 26     edge[tot].Next=head[u];
 27     head[u]=tot++;
 28 }
 29 void init_new(int n){
 30     tot=0;
 31     for(int i=0;i<=n;i++) head[i]=-1;
 32 }
 33 int root;
 34 int fa[MAX_LOG][MAX_V];
 35 void dfs(int u,int par,int d){
 36     fa[0][u]=par;
 37     depth[u]=d;
 38     for(int i=head[u];i!=-1;i=edge[i].Next){
 39         int v=edge[i].to;
 40         if(v==par) continue;
 41         dfs(v,u,d+1);
 42     }
 43 }
 44 void init(int n){
 45     root=1;
 46     dfs(root,-1,1);
 47     for(int k=0;k+1<MAX_LOG;k++){
 48         for(int v=1;v<=n;v++){
 49             fa[k+1][v]=fa[k][fa[k][v]];
 50         }
 51     }
 52 }
 53 int LCA(int u,int v){
 54     if(depth[u]>depth[v]) swap(u,v);
 55     for(int k=MAX_LOG-1;k>=0;k--){
 56         if((depth[v]-depth[u])&(1<<k)){
 57             v=fa[k][v];
 58         }
 59     }
 60     if(u==v) return u;
 61     for(int k=MAX_LOG-1;k>=0;k--){
 62         if(fa[k][u]!=fa[k][v]){
 63             u=fa[k][u];
 64             v=fa[k][v];
 65         }
 66     }
 67     return fa[0][v];
 68 }
 69 
 70 int n,m,q;
 71 struct Query{
 72     int op,u,v;
 73 } que[MAX_V*2];
 74 int num;
 75 
 76 int c[MAX_V];
 77 int lowbit(int x){
 78     return x&(-x);
 79 }
 80 void add(int x,int val){
 81     for(int i=x;i<=n;i+=lowbit(i)){
 82         c[i]+=val;
 83     }
 84 }
 85 int sum(int x){
 86     int res=0;
 87     for(int i=x;i>0;i-=lowbit(i)){
 88         res+=c[i];
 89     }
 90     return res;
 91 }
 92 
 93 int cnt;
 94 int in[MAX_V],out[MAX_V];
 95 int dfs2(int u){
 96     in[u]=++cnt;
 97     for(int i=head[u];i!=-1;i=edge[i].Next){
 98         int v=edge[i].to;
 99         if(v==fa[0][u]) continue;
100         dfs2(v);
101     }
102     out[u]=cnt;
103 }
104 
105 void solve(){
106     cnt=0; dfs2(1);
107     for(int i=1;i<=n;i++) c[i]=0;
108     for(int i=1;i<=n;i++){
109         add(in[i],1); add(out[i]+1,-1);
110     }
111     pre(n);
112     for(int i=0;i<num;i++){
113         int op=que[i].op;
114         int u=que[i].u;
115         int v=que[i].v;
116         int lca=LCA(u,v);
117         if(op==1){
118             u=find(u); v=find(v);
119             while(find(u)!=find(lca)){
120                 add(in[u],-1); add(out[u]+1,1);
121                 int par=fa[0][u];
122                 merge(u,par);
123                 u=find(u);
124             }
125             while(find(v)!=find(lca)){
126                 add(in[v],-1); add(out[v]+1,1);
127                 int par=fa[0][v];
128                 merge(v,par);
129                 v=find(v);
130             }
131         }
132         else{
133             printf("%d
",sum(in[u])+sum(in[v])-sum(in[lca])*2);
134         }
135     }
136 }
137 
138 int from[MAX_V],to[MAX_V];
139 int main(){
140     int t;
141     scanf("%d",&t);
142     int T=t;
143     while(t--){
144         scanf("%d%d",&n,&m);
145         init_new(n);
146         for(int i=1;i<=m;i++){
147             scanf("%d%d",&from[i],&to[i]);
148         }
149         num=0; pre(n);
150         for(int i=1;i<=m;i++){
151             int u=from[i];
152             int v=to[i];
153             if(find(u)==find(v)){
154                 que[num++]=(Query){1,u,v};
155             }
156             else{
157                 addedge(u,v);
158                 addedge(v,u);
159                 merge(u,v);
160             }
161         }
162         printf("Case #%d:
",T-t);
163         init(n);
164         scanf("%d",&q);
165         while(q--){
166             int op,u,v;
167             scanf("%d%d%d",&op,&u,&v);
168             que[num++]=(Query){op,u,v};
169         }
170         solve();
171     }
172 
173     return 0;
174 }
Psong

H transaction transaction transaction

两遍dfs,分别从下到上和从上到下维护买的最小值和买的最大值即可

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 
 4 typedef long long LL;
 5 
 6 const LL MAXN=1e5+5;
 7 
 8 LL n;
 9 LL a[MAXN];
10 
11 struct node{
12     LL to,cost;
13 };
14 vector<node> g[MAXN];
15 
16 LL dp1[MAXN],dp2[MAXN];
17 void dfs1(LL u,LL fa){
18     dp1[u]=a[u]; dp2[u]=a[u];
19     for(LL i=0;i<g[u].size();i++){
20         LL v=g[u][i].to;
21         LL w=g[u][i].cost;
22         if(v==fa) continue;
23         dfs1(v,u);
24         dp1[u]=max(dp1[u],dp1[v]-w);
25         dp2[u]=min(dp2[u],dp2[v]+w);
26     }
27 }
28 void dfs2(LL u,LL fa){
29     for(LL i=0;i<g[u].size();i++){
30         LL v=g[u][i].to;
31         LL w=g[u][i].cost;
32         if(v==fa) continue;
33         dp1[v]=max(dp1[v],dp1[u]-w);
34         dp2[v]=min(dp2[v],dp2[u]+w);
35         dfs2(v,u);
36     }
37 }
38 int main(){
39     LL t;
40     scanf("%lld",&t);
41     while(t--){
42         scanf("%lld",&n);
43         for(LL i=1;i<=n;i++){
44             g[i].clear();
45             scanf("%lld",&a[i]);
46         }
47         for(LL i=1;i<n;i++){
48             LL u,v,w;
49             scanf("%lld%lld%lld",&u,&v,&w);
50             g[u].push_back((node){v,w});
51             g[v].push_back((node){u,w});
52         }
53         dfs1(1,0);
54         dfs2(1,0);
55         LL ans=0;
56         for(LL i=1;i<=n;i++)
57             ans=max(ans,dp1[i]-dp2[i]);
58         printf("%lld
",ans);
59     }
60 
61     return 0;
62 }
Psong

I cube cube cube

unsolved

J ping ping ping

虽然是原题,然而当时并没有补。

贪心的做法,把所有询问排序按照lca从深到浅排序。每个询问如果端点都被标记则不计数,否则把lca的子树都给标记了并且答案++。

  1 #include <bits/stdc++.h>
  2 using namespace std;
  3 
  4 const int MAX_V=10005;
  5 const int MAX_LOG=32;
  6 vector<int> g[MAX_V];
  7 int root;
  8 int fa[MAX_LOG][MAX_V];
  9 int depth[MAX_V];
 10 void addedge(int u,int v){
 11     g[u].push_back(v);
 12     g[v].push_back(u);
 13 }
 14 void dfs(int u,int pre,int d){
 15     fa[0][u]=pre;
 16     depth[u]=d;
 17     for(int i=0;i<g[u].size();i++){
 18         int v=g[u][i];
 19         if(v==pre) continue;
 20         dfs(v,u,d+1);
 21     }
 22 }
 23 void init(int n){
 24     root=1;
 25     dfs(root,-1,0);
 26     for(int k=0;k+1<MAX_LOG;k++){
 27         for(int v=1;v<=n;v++){
 28             fa[k+1][v]=fa[k][fa[k][v]];
 29         }
 30     }
 31 }
 32 int LCA(int u,int v){
 33     if(depth[u]>depth[v]) swap(u,v);
 34     for(int k=MAX_LOG-1;k>=0;k--){
 35         if((depth[v]-depth[u])&(1<<k)){
 36             v=fa[k][v];
 37         }
 38     }
 39     if(u==v) return u;
 40     for(int k=MAX_LOG-1;k>=0;k--){
 41         if(fa[k][u]!=fa[k][v]){
 42             u=fa[k][u];
 43             v=fa[k][v];
 44         }
 45     }
 46     return fa[0][v];
 47 }
 48 
 49 int n,p;
 50 int vis[MAX_V];
 51 void dfs2(int u){
 52     if(vis[u]) return;
 53     vis[u]=1;
 54     for(int i=0;i<g[u].size();i++){
 55         int v=g[u][i];
 56         if(v==fa[0][u]) continue;
 57         dfs2(v);
 58     }
 59 }
 60 struct node{
 61     int u,v,lca;
 62 };
 63 vector<node> tt;
 64 bool cmp(node x,node y){
 65     return depth[x.lca]>depth[y.lca];
 66 }
 67 
 68 int main(){
 69     while(~scanf("%d",&n)){
 70         for(int i=1;i<=n+1;i++) g[i].clear();
 71         for(int i=1;i<=n;i++){
 72             int u,v;
 73             scanf("%d%d",&u,&v);
 74             addedge(u+1,v+1);
 75         }
 76         init(n+1);
 77         tt.clear();
 78         memset(vis,0,sizeof(vis));
 79         scanf("%d",&p);
 80         while(p--){
 81             int u,v;
 82             scanf("%d%d",&u,&v);
 83             u++,v++;
 84             tt.push_back((node){u,v,LCA(u,v)});
 85         }
 86         sort(tt.begin(),tt.end(),cmp);
 87         int ans=0;
 88         for(int i=0;i<tt.size();i++){
 89             int u=tt[i].u;
 90             int v=tt[i].v;
 91             int lca=tt[i].lca;
 92             if(vis[u]||vis[v]) continue;
 93             else{
 94                 ans++;
 95                 dfs2(lca);
 96             }
 97         }
 98         printf("%d
",ans);
 99     }
100 
101     return 0;
102 }
Psong

K triangulation triangulation triangulation

unsolved

L card card card

把串加倍一次,直接从前往后扫,扫到小于0的地方就停止,期间保证扫到的长度不超过n,记录最大值。

原文地址:https://www.cnblogs.com/N-Psong/p/7602399.html