看来(3)的倍数的天数都没有
水了一发(SA),然后(WA)
冷静分析发现我是(sb)
先搞一个(SAM),两个位置的最长公共后缀长度就是两个位置代表节点的(len[lca])
我们先把询问离线,按(r)排序,然后扫描数组
我们发现这个事情其实和树点涂色每次把一条链染上同一种颜色
如果在(access)过程中某个点已经被染色了,那么说明这个点是某两个位置的(lca),用线段树来维护最大值
注意保存两个位置时保存在左侧节点
#include<bits/stdc++.h>
using namespace std;
namespace red{
#define ls(p) (p<<1)
#define rs(p) (p<<1|1)
#define mid ((l+r)>>1)
#define lowbit(i) ((i)&(-i))
inline int read()
{
int x=0;char ch,f=1;
for(ch=getchar();(ch<'0'||ch>'9')&&ch!='-';ch=getchar());
if(ch=='-') f=0,ch=getchar();
while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
return f?x:-x;
}
const int N=4e5+10,p=1e9+7;
int n,m,tot=1,pre=1;
char s[N];
int pos[N],ret[N];
struct node
{
int l,r,id;
inline bool operator < (const node &t) const
{
return r<t.r;
}
}q[N];
struct SAM
{
int fa[N],len[N],endpos[N],son[N][2];
inline void insert(int c)
{
int p=pre,np=pre=++tot;endpos[tot]=1;
len[np]=len[p]+1;
for(;p&&!son[p][c];p=fa[p]) son[p][c]=np;
if(!p) fa[np]=1;
else
{
int q=son[p][c];
if(len[q]==len[p]+1) fa[np]=q;
else
{
int nq=++tot;
for(int i=0;i<2;++i) son[nq][i]=son[q][i];
len[nq]=len[p]+1;
fa[nq]=fa[q];
fa[q]=fa[np]=nq;
for(;p&&son[p][c]==q;p=fa[p]) son[p][c]=nq;
}
}
}
}sam;
struct SGT
{
int ans[N<<2];
inline void update(int pos,int l,int r,int p,int k)
{
// cout<<pos<<' '<<l<<' '<<r<<endl;
ans[p]=max(ans[p],k);
if(l==r) return;
if(pos<=mid) update(pos,l,mid,ls(p),k);
else update(pos,mid+1,r,rs(p),k);
}
inline int query(int tl,int tr,int l,int r,int p)
{
if(tl<=l&&r<=tr) return ans[p];
int ret=0;
if(tl<=mid) ret=query(tl,tr,l,mid,ls(p));
if(tr>mid) ret=max(ret,query(tl,tr,mid+1,r,rs(p)));
return ret;
}
}tr;
struct LCT
{
int st[N],f[N],cor[N],son[N][2];
inline void pushdown(int x)
{
if(son[x][0]) cor[son[x][0]]=cor[x];
if(son[x][1]) cor[son[x][1]]=cor[x];
}
inline bool nroot(int x)
{
return son[f[x]][0]==x||son[f[x]][1]==x;
}
inline int ident(int x)
{
return son[f[x]][1]==x;
}
inline void rotate(int x)
{
int y=f[x],z=f[y],k=son[y][1]==x,w=son[x][!k];
if(nroot(y)) son[z][son[z][1]==y]=x;son[x][!k]=y,son[y][k]=w;
if(w) f[w]=y;f[y]=x,f[x]=z;
}
inline void splay(int x)
{
int y=x,z=0;
st[++z]=y;
while(nroot(y)) st[++z]=y=f[y];
while(z) pushdown(st[z--]);
while(nroot(x))
{
y=f[x];
if(nroot(y)) rotate(ident(x)==ident(y)?y:x);
rotate(x);
}
}
inline void access(int x,int c)
{
for(int y=0;x;x=f[y=x])
{
splay(x);
if(cor[x]) tr.update(cor[x],1,n,1,sam.len[x]);
cor[x]=c;
son[x][1]=y;
}
}
}lct;
inline void main()
{
n=read(),m=read();
scanf("%s",s+1);
for(int i=1;i<=n;++i) sam.insert(s[i]-'0'),pos[i]=pre;
for(int i=tot;i;--i) lct.f[i]=sam.fa[i];
for(int i=1;i<=m;++i) q[i].l=read(),q[i].r=read(),q[i].id=i;
sort(q+1,q+m+1);
for(int i=1,j=1;i<=n&&j<=m;++i)
{
lct.access(pos[i],i);
for(;j<=m&&q[j].r<=i;++j) ret[q[j].id]=tr.query(q[j].l,i,1,n,1);
}
for(int i=1;i<=m;++i) printf("%d
",ret[i]);
}
}
signed main()
{
red::main();
return 0;
}
重心定义没有一个子树大小乘以二超过(n)
我们发现每个节点至多有一颗子树大小超过要求,而且重心在这颗子树内
很多细节。。。很难写(呜呜呜)
#include<bits/stdc++.h>
using namespace std;
namespace red{
#define ls(p) (p<<1)
#define rs(p) (p<<1|1)
#define mid ((l+r)>>1)
#define lowbit(i) ((i)&(-i))
inline int read()
{
int x=0;char ch,f=1;
for(ch=getchar();(ch<'0'||ch>'9')&&ch!='-';ch=getchar());
if(ch=='-') f=0,ch=getchar();
while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
return f?x:-x;
}
const int N=1e6+10,p=1e9+7;
int n,sum,num;
vector<int> eg[N];
inline void link(int x,int y)
{
eg[x].push_back(y);
eg[y].push_back(x);
}
int str[N],mx[N],ans[N],rt;
inline bool cmp(int x,int y){return str[x]>str[y];}
inline void find(int now,int fa)
{
str[now]=1;
for(auto t:eg[now])
{
if(t==fa) continue;
find(t,now);
mx[now]=max(mx[now],str[t]);
str[now]+=str[t];
}
mx[now]=max(mx[now],n-str[now]);
if(mx[now]<mx[rt]) rt=now;
}
inline void dfs(int now,int fa)
{
str[now]=1;
for(auto t:eg[now])
{
if(t==fa) continue;
dfs(t,now);
str[now]+=str[t];
}
}
inline void dfs2(int now,int fa,int top)
{
ans[now]=num+((n-top-str[now])*2>n);
for(auto t:eg[now])
if(t!=fa) dfs2(t,now,top);
}
inline void main()
{
n=read();
for(int x,y,i=1;i<n;++i)
{
x=read(),y=read();
link(x,y);
}
mx[0]=p;find(1,0);
dfs(rt,0);
sort(eg[rt].begin(),eg[rt].end(),cmp);
for(auto t:eg[rt])
{
sum+=str[t];
if(sum*2>=n) break;
++num;
}
for(auto t:eg[rt])
{
dfs2(t,rt,sum-max(str[t],str[eg[rt][num]]));
}
for(int i=1;i<=n;++i) printf("%d
",ans[i]);
}
}
signed main()
{
red::main();
return 0;
}
我们可以爆搜,复杂度(O(2^{100}))
我们发现一条边两个端点一定是一个左括号一个右括号,保证有解的话那么必定有偶环,复杂度上界变为
(O(2^{50}))
我们发现如果是只有(2)个点环,那么一定是靠左的那个是左括号,可以(O(1))
最坏情况变成了(4)个点的环,最多有(25)个,复杂度(O(2^{25}))
好像可做了,爆搜吧qwq
#include<bits/stdc++.h>
using namespace std;
namespace red{
#define ls(p) (p<<1)
#define rs(p) (p<<1|1)
#define mid ((l+r)>>1)
#define lowbit(i) ((i)&(-i))
inline int read()
{
int x=0;char ch,f=1;
for(ch=getchar();(ch<'0'||ch>'9')&&ch!='-';ch=getchar());
if(ch=='-') f=0,ch=getchar();
while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
return f?x:-x;
}
const int N=210,p=1e9+7;
int n;
vector<int> eg[N];
bool vis[N];
int cir[N],tot;
int c[N][N],b[N];
int ans[N];
int len[N],num;
inline void link(int x,int y)
{
eg[x].push_back(y);
eg[y].push_back(x);
}
inline void sea(int now,int fa)
{
if(vis[now]) return;
vis[now]=1;
cir[tot++]=now;
for(auto t:eg[now])
if(t!=fa) sea(t,now);
}
inline void search(int now)
{
tot=0;
sea(now,0);
if(tot==2) ans[min(cir[0],cir[1])]=1,ans[max(cir[0],cir[1])]=-1;
else
{
len[++num]=tot;
for(int i=0;i<tot;++i)
c[num][i]=cir[i],b[cir[i]]=num;
}
}
bool flag;
inline void dfs(int now,int sum)
{
if(sum<0) return;
if(now==n+1)
{
for(int i=1;i<=n;++i)
putchar(ans[i]==1?'(':')');
flag=1;return;
}
if(!ans[now])
{
ans[c[b[now]][0]]=1;
for(int i=1;i<=len[b[now]];++i)
ans[c[b[now]][i]]=-ans[c[b[now]][i-1]];
dfs(now+1,sum+ans[now]);
if(flag) return;
for(int i=0;i<len[b[now]];i++) ans[c[b[now]][i]]=-ans[c[b[now]][i]];
dfs(now+1,sum+ans[now]);
if(flag) return;
for(int i=0;i<len[b[now]];++i) ans[c[b[now]][i]]=0;
}
else dfs(now+1,sum+ans[now]);
}
inline void main()
{
n=read();
for(int i=1;i<=n;++i) link(read(),i);
for(int i=1;i<=n;++i)
if(!vis[i]) search(i);
dfs(1,0);
}
}
signed main()
{
red::main();
return 0;
}