string
description
小 A 最近喜欢上了一个字母游戏,这个游戏的大意是这样的:有 n n n 个无限长的循环字符串,所谓循环字符串,就是由某一个子串重复叠加而成。现在想知道最早在哪一位,这 n n n 个字符串位于该位的字母相同。小 A 对于简单难度的关卡简直手到擒来,但是对于困难难度的关卡他就一筹莫展了。这时他想到了你,一个机智的程序员,他希望你能够帮他编写程序求出答案。我们保证该子串中的字母互不重复,但区分大小写。
n ≤ 3 × 1 0 5 n\leq 3\times 10^5 n≤3×105
solution
最后一句话是重点
我们保证该子串中的字母互不重复,但区分大小写。
相当于是转化成了 n n n个同余方程,因为模数不互质,直接上excrt
#include <bits/stdc++.h>
using namespace std;
# define Rep(i,a,b) for(int i=a;i<=b;i++)
# define _Rep(i,a,b) for(int i=a;i>=b;i--)
# define RepG(i,u) for(int i=head[u];~i;i=e[i].next)
typedef long long ll;
const int N=30005;
template<typename T> void read(T &x){
x=0;int f=1;
char c=getchar();
for(;!isdigit(c);c=getchar())if(c=='-')f=-1;
for(;isdigit(c);c=getchar())x=(x<<1)+(x<<3)+c-'0';
x*=f;
}
# define int __int128
int n;
char s[N][60];
int a[N],p[N],x,y;
int ans=-1;
int exgcd(int a,int b,int &x,int &y){
if(!b){
x=1,y=0;
return a;
}
int d=exgcd(b,a%b,x,y);
int z=y;
y=x-a/b*y;
x=z;
return d;
}
int mul(int a,int b,int p){
int res=0;
while(b){
if(b&1)res+=a,res%=p;
a+=a,a%=p;
b>>=1;
}
return res;
}
int excrt(){
int ans=a[1],M=p[1];
Rep(i,2,n){
int GCD=exgcd(M,p[i],x,y);
int val=((a[i]-ans)%p[i]+p[i])%p[i];
if(val%GCD!=0)return -1;
x=(x%p[i]+p[i])%p[i];
int t=mul(x,val/GCD,p[i]);
ans+=t*M;
M=M/GCD*p[i];
ans=(ans%M+M)%M;
}
return ans;
}
signed main()
{
freopen("string.in","r",stdin);
freopen("string.out","w",stdout);
read(n);
Rep(i,1,n)scanf("%s",s[i]);
Rep(i,1,n)p[i]=strlen(s[i]);
Rep(i,'a','z'){
bool flag=true;
Rep(j,1,n){
int pos=-1;
for(int k=0;k<p[j];k++)if(s[j][k]==i){pos=k;break;}
if(pos==-1){flag=false;break;}
a[j]=pos;
}
if(!flag)continue;
int val=excrt();
if(val==-1)continue;
if(ans==-1)ans=val;
else ans=min(ans,val);
}
Rep(i,'A','Z'){
bool flag=true;
Rep(j,1,n){
int pos=-1;
for(int k=0;k<p[j];k++)if(s[j][k]==i){pos=k;break;}
if(pos==-1){flag=false;break;}
a[j]=pos;
}
if(!flag)continue;
int val=excrt();
if(val==-1)continue;
if(ans==-1)ans=val;
else ans=min(ans,val);
}
if(ans==-1)puts("-1");
else printf("%llu\n",(unsigned long long)ans+1);
return 0;
}
apple
description
维护一棵树
1 x 询问 询问:以某个节点 X 为根的子树的权值和
2 x k 修改 修改:将以某点 X 为根的子树上所有节点的权加上一个数 k
3 x y 修改 修改:将以某点 X 为根的整棵子树移到另一个点 Y,并成为 Y 的子树
solution
操作3灰常的恶心,先看前两个,那就是非常简单的一个dfs序
操作3本质上是交换了了dfs序,遇到交换问题,考虑平衡树
但是交换之后子树大小也会相应的变化
怎么办呢?我们可以把每个节点拆成两个,分别表示他子树在dfs区间上的左端点右端点
然后正常的做就可以了,因为每个点被算了两遍,所以操作1的答案要/2
#include <bits/stdc++.h>
using namespace std;
# define Rep(i,a,b) for(int i=a;i<=b;i++)
# define _Rep(i,a,b) for(int i=a;i>=b;i--)
# define RepG(i,u) for(int i=head[u];~i;i=e[i].next)
typedef long long ll;
const int N=3e5+5;
template<typename T> void read(T &x){
x=0;int f=1;
char c=getchar();
for(;!isdigit(c);c=getchar())if(c=='-')f=-1;
for(;isdigit(c);c=getchar())x=(x<<1)+(x<<3)+c-'0';
x*=f;
}
# define int long long
int n,m;
int head[N],cnt;
int a[N];
int dfn[N];
struct Edge{
int to,next;
}e[N<<1];
void add(int x,int y){
e[++cnt]=(Edge){y,head[x]},head[x]=cnt;
}
struct FHQ{
int fa[N],son[N][2],siz[N],tag[N],treap[N],sum[N],val[N];
int rt,tot;
void insert(int u,int k){
treap[u]=rand();
siz[u]=1;
sum[u]=val[u]=k;
rt=merge(rt,u);
}
void pushup(int x){
if(son[x][0])fa[son[x][0]]=x;
if(son[x][1])fa[son[x][1]]=x;
siz[x]=siz[son[x][0]]+siz[son[x][1]]+1;
sum[x]=sum[son[x][0]]+sum[son[x][1]]+val[x];
}
void pushdown(int x){
if(!tag[x])return;
sum[son[x][0]]+=tag[x]*siz[son[x][0]],val[son[x][0]]+=tag[x];
tag[son[x][0]]+=tag[x];
sum[son[x][1]]+=tag[x]*siz[son[x][1]],val[son[x][1]]+=tag[x];
tag[son[x][1]]+=tag[x];
tag[x]=0;
}
int merge(int u,int v){
if(!u||!v)return u|v;
int rt;
if(treap[u]<treap[v]){
pushdown(rt=u);
son[u][1]=merge(son[u][1],v);
}
else{
pushdown(rt=v);
son[v][0]=merge(u,son[v][0]);
}
return pushup(rt),rt;
}
void split(int o,int &u,int &v,int k){
if(!o){u=v=0;return;}
int rank=siz[son[o][0]]+1;
fa[o]=0;
pushdown(o);
if(rank<=k)split(son[u=o][1],son[o][1],v,k-rank);
else split(son[v=o][0],u,son[o][0],k);
pushup(o);
}
int rnk(int x){
int res=siz[son[x][0]]+1;
while(fa[x]){
if(son[fa[x]][1]==x)res+=siz[son[fa[x]][0]]+1;
x=fa[x];
}
return res;
}
}treap;
void dfs(int u,int fa){
treap.insert(u,a[u]);
RepG(i,u){
int v=e[i].to;
if(v==fa)continue;
dfs(v,u);
}
treap.insert(n+u,a[u]);
}
int query(int x){
int l=treap.rnk(x)-1,r=treap.rnk(n+x);
int lft,mid,rht;
treap.split(treap.rt,lft,rht,r);
treap.split(lft,lft,mid,l);
int res=treap.sum[mid];
treap.rt=treap.merge(treap.merge(lft,mid),rht);
return res;
}
void update(int x,int k){
int l=treap.rnk(x)-1,r=treap.rnk(n+x);
int lft,mid,rht;
treap.split(treap.rt,lft,rht,r);
treap.split(lft,lft,mid,l);
treap.val[mid]+=k;
treap.sum[mid]+=treap.siz[mid]*k;
treap.tag[mid]+=k;
treap.rt=treap.merge(treap.merge(lft,mid),rht);
}
void linkcut(int x,int y){
int l=treap.rnk(x)-1,r=treap.rnk(n+x);
int lft,mid,rht;
treap.split(treap.rt,lft,rht,r);
treap.split(lft,lft,mid,l);
treap.rt=treap.merge(lft,rht);
l=treap.rnk(y);
treap.split(treap.rt,lft,rht,l);
treap.rt=treap.merge(treap.merge(lft,mid),rht);
}
signed main()
{
// freopen("apple.in","r",stdin);
// freopen("apple.out","w",stdout);
srand(time(0));
memset(head,-1,sizeof(head));
read(n),read(m);
Rep(i,1,n)read(a[i]);
Rep(i,1,n-1){
int x,y;
read(x),read(y);
add(x,y),add(y,x);
}
dfs(1,0);
Rep(i,1,m){
int opt,x,y;
read(opt),read(x);
if(opt==1)printf("%lld\n",query(x)/2);
if(opt==2)read(y),update(x,y);
if(opt==3)read(y),linkcut(x,y);
}
return 0;
}