A:
维护一个集合,兹磁插入一个数
x
x
,询问集合里的数和做
and,or,xor
a
n
d
,
o
r
,
x
o
r
运算的最大值
权值
ai<65536=216
a
i
<
65536
=
2
16
因为位运算不同位之间互相独立,我们把一个数拆成前8位和后8位,枚举前8位dp后8位以平衡复杂度
令
f[a][b]
f
[
a
]
[
b
]
表示集合中前8位的数是
a
a
的数里,和一个后8位是的数做位运算,后8位结果的最大值
设
x
x
的前8位是,后8位是
y
y
插入时枚举
b
b
更新
询问时,枚举
a
a
,用更新答案
code:
#include<set>
#include<map>
#include<deque>
#include<queue>
#include<stack>
#include<cmath>
#include<ctime>
#include<bitset>
#include<string>
#include<vector>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<climits>
#include<complex>
#include<iostream>
#include<algorithm>
#define ll long long
using namespace std;
const int maxn = 210000;
const int maxb = 256;
int n,opt,type;
int f[maxb][maxb],g[maxb][maxb];
char str[110];
int main()
{
freopen("binary.in","r",stdin);
freopen("binary.out","w",stdout);
scanf("%d%s%d",&n,str,&type);
opt=str[0]=='a'?0:(str[0]=='o'?1:2);
for(int i=1;i<=n;i++)
{
int x; scanf("%d",&x); int y=x&255; x^=y;
if(i>1)
{
int nowmax=0,nowsum=0;
for(int j=0;j<maxb;j++)
{
int cx=f[j][y],cs=g[j][y];
if(!cs) continue;
int cj=j<<8;
cx|=opt==0?(cj&x):(opt==1?(cj|x):(cj^x));
if(cx>nowmax) nowmax=cx,nowsum=0;
if(cx==nowmax) nowsum+=cs;
}
if(type) printf("%d %d\n",nowmax,nowsum);
else printf("%d\n",nowmax);
}
x>>=8;
for(int j=0;j<maxb;j++)
{
int cx=opt==0?(y&j):(opt==1?(y|j):(y^j));
if(f[x][j]<cx) f[x][j]=cx,g[x][j]=0;
if(f[x][j]==cx) g[x][j]++;
}
}
return 0;
}
B:
一开始有个空串,
n
n
次操作,每次操作形如在第次操作后的串尾添加一个字符
x
x
并且询问操作完的串最小周期的长度,强制在线
对于串
S
S
,有,即他的最小周期=串长减最长的border(border就是一段和后缀相等的前缀)
于是考虑怎么求这个串的
border
b
o
r
d
e
r
,假设我们对这个单串建AC自动机,发现
border
b
o
r
d
e
r
就是这个串的
fail
f
a
i
l
的长度
问题变成在线维护一个AC自动机,要求每个点只能
fail
f
a
i
l
到他的祖先上
加入一个点时如果我们暴力去跳
fail
f
a
i
l
显然会T,于是我们要对每个节点维护一个
son[26]
s
o
n
[
26
]
,表示在他后面接上字符
c
c
,会跳到哪个节点
那这个东西要怎么在线维护呢
考虑在某个点后面接上一个字符
c
c
后我们要更新哪些信息
我们要新建一个点 代表在
x
x
后面接上字符后的串
然后更新
x
x
的,维护
y
y
的,
y
y
的,
y
y
的
这个东西显然只能可持久化维护,但是注意到如果我们更新了
x
x
的,因为可持久化我们会新建一个
x′
x
′
,那么我们这个串上所有原来
son
s
o
n
指向
x
x
的都要更新,指向,这样子我们单次插入更新的信息量十分巨大完全无法承受
所以我们要改一下
son
s
o
n
和
fail
f
a
i
l
的定义,改成指向原来应该指向的点代表的串的长度
len
l
e
n
,比如原来
son[a]
s
o
n
[
a
]
和
fail[b]
f
a
i
l
[
b
]
都指向点
c
c
,现在他们要指向
然后我们再对每个点可持久化每个长度
len
l
e
n
下标对应的点
id[len]
i
d
[
l
e
n
]
这样我们插入
c
c
的时候,只要更新的
son
s
o
n
,用
fail[x]
f
a
i
l
[
x
]
维护
fail[y]
f
a
i
l
[
y
]
,
son[y]
s
o
n
[
y
]
就继承
son[fail[y]]
s
o
n
[
f
a
i
l
[
y
]
]
,再维护
y
y
的就行了
复杂度 O(nlogn) O ( n l o g n )
code:
#include<set>
#include<map>
#include<deque>
#include<queue>
#include<stack>
#include<cmath>
#include<ctime>
#include<bitset>
#include<string>
#include<vector>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<climits>
#include<complex>
#include<iostream>
#include<algorithm>
#define ll long long
using namespace std;
inline void read(int &x)
{
char c; while(!((c=getchar())>='0'&&c<='9'));
x=c-'0';
while((c=getchar())>='0'&&c<='9') (x*=10)+=c-'0';
}
const int maxn = 610000;
const int maxp = maxn*25;
int n,m,type;
struct segment
{
int cnt;
int seg[maxp],lc[maxp],rc[maxp];
int loc,c;
int newnode(int x)
{
++cnt;
lc[cnt]=lc[x],rc[cnt]=rc[x];
seg[cnt]=seg[x];
return cnt;
}
void upd(int &x,const int l,const int r)
{
x=newnode(x);
if(l==r){ seg[x]=c;return; }
int mid=(l+r)>>1;
loc<=mid?upd(lc[x],l,mid):upd(rc[x],mid+1,r);
}
int q(int x,const int l,const int r)
{
if(l==r) return seg[x];
int mid=(l+r)>>1;
return loc<=mid?q(lc[x],l,mid):q(rc[x],mid+1,r);
}
}Son,P;
int tot,fl[maxn],len[maxn],rootp[maxn],rootson[maxn];
int stri[maxn];
int ans;
void add(int i,int x,int c)
{
x=stri[x];
int now=++tot; stri[i]=now;
len[now]=len[x]+1;
int y=++tot; fl[y]=fl[x],len[y]=len[x],rootp[y]=rootp[x],rootson[y]=rootson[x];
P.loc=len[y],P.c=y,P.upd(rootp[y],0,n);
P.loc=fl[y]; int tmp=P.q(rootp[y],0,n);
Son.loc=c; tmp=Son.q(rootson[tmp],1,m);
P.loc=tmp; tmp=P.q(rootp[y],0,n);
Son.loc=c,Son.c=len[now],Son.upd(rootson[y],1,m);
fl[now]=len[tmp];
rootp[now]=rootp[y];
P.loc=len[now],P.c=now,P.upd(rootp[now],0,n);
rootson[now]=rootson[tmp];
//P.loc=0,printf("%d\n",P.q(rootp[now],0,n));
//Son.loc=1; int temp=Son.q(rootson[now],1,m);
//int ii=1;
}
int main()
{
freopen("string.in","r",stdin);
freopen("string.out","w",stdout);
read(n); read(m); read(type);
for(int i=1;i<=n;i++)
{
int x,c; read(x); read(c);
x^=ans,c^=ans;
add(i,x,c);
printf("%d\n",ans=(len[stri[i]]-fl[stri[i]]));
ans*=type;
}
return 0;
}
C:
显然要对每个
k
k
,预处理出表示有多少个
(x,y)
(
x
,
y
)
,满足
f(x,y)=k
f
(
x
,
y
)
=
k
如果暴力的做,就是枚举
x
x
,然后以为根,dfs一遍整棵树,我们将
′(′
′
(
′
视为1,
′)′
′
)
′
视为-1,如果
S(x,y)
S
(
x
,
y
)
满足任意前缀非负任意后缀非正,然后我们就可以
O(n2)
O
(
n
2
)
的处理出这个东西
要加速这个暴力的话,考虑点分治,对每个分治中心
x
x
往下dfs下去分别搜可以作为左半边的串和可以作为右半边的串,比如左半边的串,要求从到
y
y
,任意后缀非负,且和为正,设和为,拿他和右半边的和为
−s
−
s
的那些串合并,合并的时候可以用FFT加速
因为对于每个分治中心去计算答案是,设当前树的大小是
n
n
的,合并时多项式的次数和是的,这次计算的复杂度是
O(nlogn)
O
(
n
l
o
g
n
)
所以总复杂度是
O(nlog2n)
O
(
n
l
o
g
2
n
)
的
code:
#include<set>
#include<map>
#include<deque>
#include<queue>
#include<stack>
#include<cmath>
#include<ctime>
#include<bitset>
#include<string>
#include<vector>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<climits>
#include<complex>
#include<iostream>
#include<algorithm>
#define ll long long
#define pb push_back
#define SZ(x) (int)x.size()
using namespace std;
inline void read(int &x)
{
char c; while(!((c=getchar())>='0'&&c<='9'));
x=c-'0';
while((c=getchar())>='0'&&c<='9') (x*=10)+=c-'0';
}
inline void up(int &a,const int &b){if(a<b)a=b;}
const int maxn = 210000;
const double pi = acos(-1);
namespace FFT
{
struct E
{
double x,y;
friend inline E operator +(const E &x,const E &y){return (E){x.x+y.x,x.y+y.y};}
friend inline E operator -(const E &x,const E &y){return (E){x.x-y.x,x.y-y.y};}
friend inline E operator *(const E &x,const E &y){return (E){x.x*y.x-x.y*y.y,x.x*y.y+x.y*y.x};}
}s1[maxn],s2[maxn];
int N,id[maxn],ln;
void dft(E f[],int sig)
{
for(int i=0;i<N;i++) if(i<id[i]) swap(f[i],f[id[i]]);
for(int m=2;m<=N;m<<=1)
{
int t=m>>1;
E w=(E){cos(2*pi/m),sin(2*pi*sig/m)};
for(int j=0;j<N;j+=m)
{
E wn=(E){1,0};
for(int i=0;i<t;i++)
{
E tx=f[j+i],ty=f[j+i+t]*wn;
f[j+i]=tx+ty;
f[j+i+t]=tx-ty;
wn=wn*w;
}
}
}
if(sig==-1)
{
for(int i=0;i<N;i++) f[i].x/=(double)N;
}
}
void solve(int f[],int g[],int fn,int gn)
{
N=1,ln=0;
while(N<=fn+gn) N<<=1,ln++;
for(int i=1;i<N;i++) id[i]=id[i>>1]>>1|(i&1)<<(ln-1);
for(int i=0;i<=fn;i++) s1[i]=(E){(double)f[i],0};
for(int i=fn+1;i<N;i++) s1[i]=(E){0,0};
for(int i=0;i<=gn;i++) s2[i]=(E){(double)g[i],0};
for(int i=gn+1;i<N;i++) s2[i]=(E){0,0};
dft(s1,1); dft(s2,1);
for(int i=0;i<N;i++) s1[i]=s1[i]*s2[i];
dft(s1,-1);
for(int i=0;i<N;i++) f[i]=(int)(s1[i].x+0.5);
}
}
int n,m;
int c[maxn];
ll ans[maxn];
struct edge{int y,nex;}a[maxn<<1]; int len,fir[maxn],v[maxn];
inline void ins(const int x,const int y){a[++len]=(edge){y,fir[x]};fir[x]=len;}
int siz[maxn];
int findrt(int x,int fa,int N)
{
siz[x]=1; int mxs=0;
for(int k=fir[x],y=a[k].y;k;k=a[k].nex,y=a[k].y) if(!v[k]&&y!=fa)
{
int re=findrt(y,x,N); if(re) return re;
siz[x]+=siz[y];
up(mxs,siz[y]);
}
if(mxs*2<=N&&(N-siz[x])*2<=N) return x;
return 0;
}
vector<int>Vl[maxn],Vr[maxn];
int lx,rx;
void dfsl(int x,int fa,int sum,int mx,int now)
{
siz[x]=1;
sum+=c[x]; up(lx,sum);
if(sum>mx) mx=sum,now=-1;
if(sum==mx) Vl[sum].pb(++now);
for(int k=fir[x],y=a[k].y;k;k=a[k].nex,y=a[k].y) if(y!=fa&&!v[k])
dfsl(y,x,sum,mx,now),siz[x]+=siz[y];
}
void dfsr(int x,int fa,int sum,int mn,int now)
{
sum+=c[x]; up(rx,-sum);
if(sum<mn) mn=sum,now=-1;
if(sum==mn) Vr[-sum].pb(++now);
for(int k=fir[x],y=a[k].y;k;k=a[k].nex,y=a[k].y) if(y!=fa&&!v[k])
dfsr(y,x,sum,mn,now);
}
int f[maxn],g[maxn],fn,gn;
void calc(int sig)
{
for(int i=0,ui=min(lx,rx);i<=ui;i++)
{
for(int j=0;j<=fn+gn;j++) f[j]=g[j]=0;
fn=gn=0;
for(int j=0;j<SZ(Vl[i]);j++)
{
int x=Vl[i][j];
f[x]++; up(fn,x);
}
for(int j=0;j<SZ(Vr[i]);j++)
{
int x=Vr[i][j];
g[x]++; up(gn,x);
}
FFT::solve(f,g,fn,gn);
for(int j=0;j<=fn+gn;j++) ans[j+(i>0)]+=f[j]*sig;
}
}
void Divide_And_Conquer(int x,int N)
{
x=findrt(x,0,N);
while(lx>=0) Vl[lx--].clear();
while(rx>=0) Vr[rx--].clear();
dfsl(x,0,0,0,0);
Vr[rx=0].pb(0);
for(int k=fir[x],y=a[k].y;k;k=a[k].nex,y=a[k].y) if(!v[k])
dfsr(y,x,0,0,0);
calc(1);
for(int k=fir[x],y=a[k].y;k;k=a[k].nex,y=a[k].y) if(!v[k])
{
while(lx>=0) Vl[lx--].clear();
while(rx>=0) Vr[rx--].clear();
dfsl(y,x,c[x],max(c[x],0),0);
dfsr(y,x,0,0,0);
calc(-1);
}
for(int k=fir[x],y=a[k].y;k;k=a[k].nex,y=a[k].y) if(!v[k])
{
v[k]=v[k^1]=1;
Divide_And_Conquer(y,siz[y]);
}
}
char str[110];
int main()
{
freopen("inverse.in","r",stdin);
freopen("inverse.out","w",stdout);
len=1;
read(n);
for(int i=1;i<n;i++)
{
int x,y; read(x),read(y);
ins(x,y),ins(y,x);
}
for(int i=1;i<=n;i++)
{
scanf("%s",str);
c[i]=str[0]=='('?1:-1;
}
Divide_And_Conquer(1,n);
read(m);
while(m--)
{
int x; read(x);
printf("%lld\n",ans[x]);
}
return 0;
}