两种操作:
1.输入X,s,t,对于链s-t,设上面的点为
v1,..,k
,给
vi
加上
iXRi
。
2.输入s,t,询问链s-t的权值和,对100711433取模。
所有操作1的R相同,在一开始会给出。
所以操作1在操作2之后出现,操作1有U个,操作2有Q个。
1≤n,Q,U≤105,1≤R,X≤109
时限1.5s,空间限制256MB。
想出标算的时候就剩1个半小时了,然后自不量力开始码标算,然后开始各种推错式子,最后还是交了暴力,结果暴力爆零了。
原因是因为暴力用dfs序对付了询问,结果bit的时候把n<<1写成了1
<<
n;然后试了几组小数据没有问题,大数据就吃翔了。
标算的话。。既然修改和询问是分开的,也就是说如果我们能先把每个点的点权搞出来,然后就可以直接上dfs序+bit了。
那么问题在于修改的贡献该如何累积,注意这个式子
XiRi
,它本身虽然不太好求,但它的前缀我们是回求的,那我们求一下前缀然后差分一下就好了。
然后显然可以就可以维护 ∑XiaiRai 和 ∑XiRai ,我一开始想的是维护当前的和前一个的然后求点权的时候再减,但后来发现(写起来太吃屎了)其实反正都有什么分配律什么的,直接维护差分后的就行。
因为这是区间修改、单点查询,所以我们考虑差分序列。搞出原树的重链,然后把每一个修改对于每一条链打一个载入标记和一个载出标记;注意到因为一个修改需要先上去再下去走两遍,所以要打两遍标记。因为一条链只会跨过 log2n 的重链,所以这样做的时间复杂度是 O(nlog2n) 的。
打完标记以后就是说我们需要面对这样一个事情,知道当前的 ∑XiaiRai 和 ∑XiRai ,怎么求 ∑Xi(ai+1)Rai+1 和 ∑XiRai+1 ?显然, ∑XiRai+1 = R∑XiRai , ∑Xi(ai+1)Rai+1=R∑XiaiRai+∑XiaiRai+1 ,这样我们就以搞了。
但是还有一个问题,注意到分母上出现了R-1,那么就要求R-1有逆元,可如果R-1没有逆元怎么办?100711433是个质数,所以R-1没有逆元,当且仅当 R−1=0(mod 100711433) ,也就是 R=1(mod 100711433) ,所以我们需要单独处理这种蛋疼的情况,显然这时
然后。。总时间复杂度
O(nlog2n)
思路还算尚可,代码就直接吃翔了。
代码(暴力):
#include<cstdio>
#include<cstring>
#include<iostream>
#include<cstdlib>
using namespace std;
#define Mod 100711433
char * cp=(char *)malloc(10000000);
inline void in(int &x){
while(*cp<'0'||*cp>'9')++cp;
x=0;
while(*cp>='0'&&*cp<='9')x=x*10+(*cp++^'0');
}
int ptr[100005],succ[200005],next[200005],etot=1;
inline void addedge(int u,int v){
next[etot]=ptr[u],ptr[u]=etot,succ[etot++]=v;
}
int fa[100005][18],depth[100005],bl[100005],br[100005],btot=1;
void dfs(int node){
depth[node]=depth[fa[node][0]]+1;
bl[node]=btot++;
for(int i=ptr[node];i;i=next[i])
if(succ[i]!=fa[node][0]){
fa[succ[i]][0]=node;
for(int j=1;j<18;++j)fa[succ[i]][j]=fa[fa[succ[i]][j-1]][j-1];
dfs(succ[i]);
}
br[node]=btot++;
}
int path[100005];
typedef long long LL;
LL fac[100005];
int p[100005];
int n;
int bit[200005];
void add(int x,int A){
for(;x<=1<<n;x+=x&-x)bit[x]=(bit[x]+A)%Mod;
}
int query(int x){
int ans=0;
for(;x;x-=x&-x)ans=(ans+bit[x])%Mod;
return ans;
}
int main(){
freopen("tree.in","r",stdin);
freopen("tree_50.out","w",stdout);
fread(cp,1,10000000,stdin);
int U,Q,R,i;
in(n),in(R);
fac[0]=1;
for(i=1;i<=n;++i)fac[i]=fac[i-1]*R%Mod;
int u,v;
for(i=n;--i;){
in(u),in(v);
addedge(u,v),addedge(v,u);
}
in(U),in(Q);
int root=(rand()<<16|rand())%n+1;
dfs(root);
int s,t,ptot,X;
while(U--){
in(X),in(s),in(t);
u=s,v=t;
ptot=0;
while(u!=v)
if(depth[u]>depth[v]){
path[ptot++]=u;
u=fa[u][0];
}
else v=fa[v][0];
path[ptot++]=u;
v=t;
ptot+=depth[v]-depth[u];
for(;u!=v;v=fa[v][0])path[--ptot]=v;
ptot+=depth[t]-depth[u];
for(i=0;i<ptot;++i)p[path[i]]=(p[path[i]]+X*fac[i+1]%Mod*(i+1)%Mod)%Mod;
}
for(i=n;i;--i)add(bl[i],p[i]),add(br[i],-p[i]);
int ans;
while(Q--){
in(s),in(t);
ans=(query(bl[s])+query(bl[t]))%Mod;
if(depth[s]>depth[t])swap(s,t);
for(i=18;i--;)
if(1<<i&depth[t]-depth[s])
t=fa[t][i];
for(i=18;i--;)
if(fa[s][i]!=fa[t][i])
s=fa[s][i],t=fa[t][i];
if(s!=t)s=fa[s][0];
ans=((ans-(query(bl[s])+query(bl[fa[s][0]]))%Mod)%Mod+Mod)%Mod;
printf("%d\n",ans);
}
}
代码(标算):
#include<cstdio>
#include<cstring>
#include<cmath>
#include<iostream>
using namespace std;
#include<cstdlib>
#define Mod 100711433
char * cp=(char *)malloc(10000000);
int ptr[100005],succ[200005],next[200005],etot=1;
inline void in(int &x){
while(*cp<'0'||*cp>'9')++cp;
x=0;
while(*cp>='0'&&*cp<='9')x=x*10+(*cp++^'0');
}
inline void addedge(int u,int v){
next[etot]=ptr[u],ptr[u]=etot,succ[etot++]=v;
}
typedef long long LL;
inline int pow(int a,int b){
LL ans=1,t=a;
for(;b;b>>=1,t=t*t%Mod)
if(b&1)
ans=ans*t%Mod;
return ans;
}
LL sr[100005],sir[100005];//R≠1
LL sum2[100005],sum1[100005];
int fa[100005],size[100005],depth[100005],maxson[100005],top[100005];
void sizedfs(int node){
depth[node]=depth[fa[node]]+1;
size[node]=1;
for(int i=ptr[node];i;i=next[i])
if(succ[i]!=fa[node]){
fa[succ[i]]=node;
sizedfs(succ[i]);
size[node]+=size[succ[i]];
}
}
int bl[100005],br[100005],btot=1;
LL bit[200005];
void builddfs(int node,int wt){
top[node]=wt;
bl[node]=btot++;
for(int i=ptr[node];i;i=next[i])
if(succ[i]!=fa[node]&&size[succ[i]]>size[maxson[node]])
maxson[node]=succ[i];
if(maxson[node]){
builddfs(maxson[node],wt);
for(int i=ptr[node];i;i=next[i])
if(succ[i]!=maxson[node]&&succ[i]!=fa[node])
builddfs(succ[i],succ[i]);
}
br[node]=btot++;
}
int p[100005],s[100005],t[100005],X[100005],lca[100005];
LL fac[100005];
inline LL multi(int x){
return (LL)x*x%Mod;
}
LL nowsr,nowsir;//R≠1
LL nowsum2,nowsum1;
int niyuan;
inline void add1(int node,int dis,int X){
sum2[node]=(sum2[node]+(multi(dis)-multi(dis-1))%Mod*X%Mod)%Mod;
sum1[node]=(sum1[node]+X)%Mod;
//cout<<"Add:"<<node<<","<<dis<<","<<X<<"->"<<sum2[node]<<" "<<sum1[node]<<endl;
}
inline void minus1(int node,int dis,int X){
sum2[node]=(sum2[node]-(multi(dis)-multi(dis-1))%Mod*X%Mod)%Mod;
sum1[node]=(sum1[node]-X)%Mod;
//cout<<"Minus:"<<node<<","<<dis<<","<<X<<"->"<<sum2[node]<<" "<<sum1[node]<<endl;
}
inline void update1(int node){
nowsum2=(nowsum2+(nowsum1<<1))%Mod;
nowsum2=(nowsum2+sum2[node])%Mod;
nowsum1=(nowsum1+sum1[node])%Mod;
p[node]=(p[node]+(nowsum2+nowsum1)%Mod*niyuan%Mod)%Mod;
//cout<<"Update:"<<node<<":"<<nowsum2<<","<<nowsum1<<"->"<<p[node]<<endl;
}
inline void add(int node,int dis,int X){
sum2[node]=(sum2[node]+(dis*fac[dis]%Mod-(dis-1)*fac[dis-1]%Mod)%Mod*X%Mod)%Mod;
sum1[node]=(sum1[node]+(fac[dis]-fac[dis-1])%Mod*X%Mod)%Mod;
//cout<<"Add:"<<node<<","<<dis<<","<<X<<"->"<<sum2[node]<<","<<sum1[node]<<" "<<fac[dis]%Mod*X%Mod<<endl;
}
inline void minu(int node,int dis,int X){
sum2[node]=(sum2[node]-(dis*fac[dis]%Mod-(dis-1)*fac[dis-1]%Mod)%Mod*X%Mod)%Mod;
sum1[node]=(sum1[node]-(fac[dis]-fac[dis-1])%Mod*X%Mod)%Mod;
//cout<<"Minus:"<<node<<","<<dis<<","<<X<<"->"<<sum2[node]<<","<<sum1[node]<<" "<<fac[dis]%Mod*X%Mod<<endl;
}
inline void update(int node){
nowsum1=nowsum1*fac[1]%Mod;
nowsum2=(nowsum2*fac[1]%Mod+nowsum1)%Mod;
nowsum2=(nowsum2+sum2[node])%Mod;
nowsum1=(nowsum1+sum1[node])%Mod;
p[node]=(p[node]+(nowsum2-nowsum1*niyuan)%Mod*fac[1]%Mod*niyuan)%Mod;
//cout<<"Update:"<<node<<":"<<nowsum2<<","<<nowsum1<<"->"<<p[node]<<endl;
}
int n;
inline void badd(int x,int A){
for(;x<=n<<1;x+=x&-x)bit[x]=(bit[x]+A)%Mod;
}
inline int bQ(int x){
int ans=0;
for(;x;x-=x&-x)ans=(ans+bit[x])%Mod;
return ans;
}
int main(){
freopen("tree.in","r",stdin);
freopen("tree.out","w",stdout);
fread(cp,1,10000000,stdin);
int i,j,u,v,R;
in(n),in(R);
R%=Mod;
fac[0]=1;
for(i=1;i<=n;++i)fac[i]=fac[i-1]*R%Mod;
for(i=n;--i;){
in(u),in(v);
addedge(u,v),addedge(v,u);
}
int root=(rand()<<16|rand())%n+1;
sizedfs(root);
builddfs(root,root);
int U,Q;
in(U),in(Q);
//搞出p[i]
for(i=U;i--;){
in(X[i]),in(s[i]),in(t[i]);
u=s[i],v=t[i];
while(top[u]!=top[v])
if(depth[top[u]]>depth[top[v]])u=fa[top[u]];
else v=fa[top[v]];
if(depth[u]>depth[v])lca[i]=v;
else lca[i]=u;
}
if(R==1)niyuan=pow(2,Mod-2);
else niyuan=pow(R-1,Mod-2);
int node;
if(R==1){
//上去。(包含lca)
for(i=U;i--;){
for(u=s[i];top[u]!=top[lca[i]];u=fa[top[u]])add1(u,depth[s[i]]-depth[u]+1,X[i]);
add1(u,depth[s[i]]-depth[u]+1,X[i]);
if(lca[i]!=top[lca[i]])minus1(fa[lca[i]],depth[s[i]]-depth[lca[i]]+2,X[i]);
}
for(i=n;i;--i)
if(maxson[i]==0){
nowsum2=nowsum1=0;
for(node=i;top[node]==top[i];node=fa[node])update1(node);
}
/*for(i=1;i<=n;++i)cout<<p[i]<<" ";
cout<<endl;*/
//cout<<"-------------\n";
//下来
memset(sum2,0,sizeof(sum2));
memset(sum1,0,sizeof(sum1));
for(i=U;i--;){
for(v=t[i];top[v]!=top[lca[i]];v=fa[top[v]]){
add1(top[v],depth[top[v]]-depth[lca[i]]+depth[s[i]]-depth[lca[i]]+1,X[i]);
if(maxson[v])minus1(maxson[v],depth[v]-depth[lca[i]]+depth[s[i]]-depth[lca[i]]+2,X[i]);
}
if(v!=lca[i]&&maxson[lca[i]]){
add1(maxson[lca[i]],depth[s[i]]-depth[lca[i]]+2,X[i]);
if(maxson[v])minus1(maxson[v],depth[s[i]]-depth[lca[i]]+depth[v]-depth[lca[i]]+2,X[i]);
}
}
for(i=n;i;--i)
if(top[i]==i){
nowsum2=nowsum1=0;
for(node=i;node;node=maxson[node])update1(node);
}
/*for(i=1;i<=n;++i)cout<<p[i]<<" ";
cout<<endl;*/
}
else{
//上去。(包含lca)
for(i=U;i--;){
for(u=s[i];top[u]!=top[lca[i]];u=fa[top[u]])add(u,depth[s[i]]-depth[u]+1,X[i]);
add(u,depth[s[i]]-depth[u]+1,X[i]);
if(top[lca[i]]!=lca[i])minu(fa[lca[i]],depth[s[i]]-depth[lca[i]]+2,X[i]);
}
for(i=n;i;--i)
if(maxson[i]==0){
nowsum2=nowsum1=0;
for(node=i;top[node]==top[i];node=fa[node])update(node);
}
//下来.不包含lca。
//cout<<"----------\n";
memset(sum2,0,sizeof(sum2));
memset(sum1,0,sizeof(sum1));
for(i=U;i--;){
for(v=t[i];top[v]!=top[lca[i]];v=fa[top[v]]){
add(top[v],depth[top[v]]-depth[lca[i]]+depth[s[i]]-depth[lca[i]]+1,X[i]);
if(maxson[v])minu(maxson[v],depth[v]-depth[lca[i]]+depth[s[i]]-depth[lca[i]]+2,X[i]);
}
if(v!=lca[i]&&maxson[lca[i]]){
add(maxson[lca[i]],depth[s[i]]-depth[lca[i]]+2,X[i]);
if(maxson[v])minu(maxson[v],depth[s[i]]-depth[lca[i]]+depth[v]-depth[lca[i]]+2,X[i]);
}
}
for(i=n;i;--i)
if(top[i]==i){
nowsum2=nowsum1=0;
for(node=i;node;node=maxson[node])update(node);
}
}
for(i=n;i;--i){
p[i]=(p[i]+Mod)%Mod;
badd(bl[i],p[i]),badd(br[i],-p[i]);
}
//回答询问
LL ans=0;
while(Q--){
in(u),in(v);
ans=(bQ(bl[u])+bQ(bl[v]))%Mod;
while(top[u]!=top[v])
if(depth[top[u]]>depth[top[v]])u=fa[top[u]];
else v=fa[top[v]];
if(depth[u]>depth[v])swap(u,v);
ans=((ans-bQ(bl[u])-bQ(bl[fa[u]]))%Mod+Mod)%Mod;
printf("%d\n",ans);
}
}
总结:
①以后比赛还剩个15min或20min的时候一定不要再写了,一定要给目前写出来的要交的程序出数据:出小数据、卡下界,出特殊数据、比如说链什么的,然后出一些可以手算的和随机的大数据。
②推式子的时候一定要仔细!
③一定要擅长使用函数,让代码和思路更清晰。