不想去听老师读PPT上的公式,来统一更一下网络赛的情况。。。。。
后缀数组,连续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 }
保证每个颜色至少出现在(m-k+1)个屏幕上即可。
unsolved
分别最长不下降子序列和最长不上升子序列
矩阵快速幂 f[2*n+3]-1
最长的步伐不超过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 }
一开始写了个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 }
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 }
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 }
unsolved
虽然是原题,然而当时并没有补。
贪心的做法,把所有询问排序按照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 }
K triangulation triangulation triangulation
unsolved
把串加倍一次,直接从前往后扫,扫到小于0的地方就停止,期间保证扫到的长度不超过n,记录最大值。