各位刷BZOJ的朋友们千万不要同cincout,会RE的!!!
各位刷BZOJ的朋友们千万不要同cincout,会RE的!!!
各位刷BZOJ的朋友们千万不要同cincout,会RE的!!!
题目
给定一棵树,设计数据结构支持以下操作
1 u v d 表示将路径 (u,v) 加d
2 u v 表示询问路径 (u,v) 上点权绝对值的和
思路
明显是个树链剖分嘛
废话!我就是找的树链剖分的题目!!
这个线段树那里的话暴力修改需要把值弄成正的那种就可以了啊 ,维护一个负数的最大值和负数个数
感觉可以用树状数组,但是涉及到要最值来暴力修改,因此树状数组应该是行不通的
还有就是记得开LL,很多地方都要开LL。
时间复杂度应该是O(mlognlogn+nlogn )
码后感
真的不想说什么,怎么会有不能用cout的题库嘛!?
然后写了一下午,当然也充满了我自己代码的问题,然后写了对拍,因此我决定对于所有我写了对拍程序的数据生成、暴力都贴上来,供大家取用。
关于树剖
说说算法吧,一般来说两个板块都有可能错,不过按道理来说树剖写错的概率不大,因此重点还是数据结构,树剖嘛,本身也没有什么难点的。
代码(数据生成、暴力、对拍在后面)
正解
#include<cmath>
#include<queue>
#include<cstdio>
#include<cctype>
#include<vector>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long LL;
const int maxn=1e5+100;
const LL inf=1e14;
int np,first[maxn];
struct edge{
int to,next;
}E[maxn<<1];
void add(int u,int v)
{
E[++np]=(edge){v,first[u]};
first[u]=np;
}
int w[maxn],a[maxn];
struct SegmentTree
{
int rt,np,lc[maxn<<1],rc[maxn<<1],cnt[maxn<<1];
LL sum[maxn<<1],down[maxn<<1],mx[maxn<<1];
void Initial()
{
rt=np=0;
memset(lc,0,sizeof(lc));
memset(rc,0,sizeof(rc));
memset(mx,0,sizeof(mx));
memset(cnt,0,sizeof(cnt));
memset(sum,0,sizeof(sum));
memset(down,0,sizeof(down));
}
void pushup(int now)
{
cnt[now]=cnt[lc[now]]+cnt[rc[now]];
mx[now]=max(mx[lc[now]],mx[rc[now]]);
sum[now]=sum[lc[now]]+sum[rc[now]];
}
void pushdown(int now,int L,int R)
{
if(down[now])
{
int m=(L+R)>>1;
mx[lc[now]]+=down[now];
sum[lc[now]]+=down[now]*(m-L+1-2*cnt[lc[now]]);
down[lc[now]]+=down[now];
mx[rc[now]]+=down[now];
sum[rc[now]]+=down[now]*(R-m-2*cnt[rc[now]]);
down[rc[now]]+=down[now];
down[now]=0;
}
}
void build(int &now,int L,int R)
{
now=++np;
if(L==R)
{
mx[now]=a[L]<0?a[L]:-inf;
cnt[now]=a[L]<0?1:0;
sum[now]=abs(a[L]);
return;
}
int m=(L+R)>>1;
build(lc[now],L,m);
build(rc[now],m+1,R);
pushup(now);
}
LL query(int now,int L,int R,int i,int j)
{
if(i<=L && R<=j)return sum[now];
pushdown(now,L,R);
int m=(L+R)>>1;
LL ret=0;
if(i<=m)ret+=query(lc[now],L,m,i,j);
if(j>m)ret+=query(rc[now],m+1,R,i,j);
return ret;
}
void modify(int now,int L,int R,int i,int j,int v)
{
if(L==R)
{
if(mx[now]+v>=0)
{
cnt[now]=0;
sum[now]=mx[now]+v;
mx[now]=-inf;
}
else
{
if(cnt[now])
{
sum[now]-=v;
mx[now]=-sum[now];
}
else
sum[now]+=v;
}
return;
}
if(i<=L && R<=j && mx[now]+v<0)
{
mx[now]+=v;
down[now]+=v;
sum[now]+=1ll*v*(R-L+1-2*cnt[now]);
return;
}
pushdown(now,L,R);
int m=(L+R)>>1;
if(i<=m)modify(lc[now],L,m,i,j,v);
if(j>m)modify(rc[now],m+1,R,i,j,v);
pushup(now);
}
}sgt;
int n,m;
int dfn,sz[maxn],dep[maxn],son[maxn],fa[maxn],tr[maxn],top[maxn];
void DFS1(int i,int f,int d)
{
sz[i]=1,dep[i]=d,fa[i]=f,son[i]=0;
for(int p=first[i];p;p=E[p].next)
{
int j=E[p].to;
if(j==f)continue;
DFS1(j,i,d+1);
if(sz[son[i]]<sz[j])son[i]=j;
sz[i]+=sz[j];
}
}
void DFS2(int i,int tp)
{
top[i]=tp,tr[i]=++dfn;
if(son[i])DFS2(son[i],tp);
for(int p=first[i];p;p=E[p].next)
{
int j=E[p].to;
if(j==fa[i] || j==son[i])continue;
DFS2(j,j);
}
}
void modify(int x,int y,int v)
{
while(top[x]!=top[y])
{
if(dep[top[x]]<dep[top[y]])swap(x,y);
sgt.modify(sgt.rt,1,n,tr[top[x]],tr[x],v);
x=fa[top[x]];
}
if(dep[x]<dep[y])swap(x,y);
sgt.modify(sgt.rt,1,n,tr[y],tr[x],v);
}
LL query(int x,int y)
{
LL ret=0;
while(top[x]!=top[y])
{
if(dep[top[x]]<dep[top[y]])swap(x,y);
ret+=sgt.query(sgt.rt,1,n,tr[top[x]],tr[x]);
x=fa[top[x]];
}
if(dep[x]<dep[y])swap(x,y);
ret+=sgt.query(sgt.rt,1,n,tr[y],tr[x]);
return ret;
}
void Init()
{
int u,v;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
scanf("%d",&w[i]);
for(int i=1;i<n;i++)
{
scanf("%d%d",&u,&v);
add(u,v);
add(v,u);
}
DFS1(1,0,1);
DFS2(1,1);
for(int i=1;i<=n;i++)
a[tr[i]]=w[i];
sgt.Initial();
sgt.build(sgt.rt,1,n);
}
void solve()
{
int op,u,v,d;
while(m--)
{
scanf("%d",&op);
if(op==1)
{
scanf("%d%d%d",&u,&v,&d);
modify(u,v,d);
}
else
{
scanf("%d%d",&u,&v);
cout<<query(u,v)<<endl;
}
}
}
int main()
{
/*freopen("in.txt","r",stdin);
freopen("out1.txt","w",stdout);*/
Init();
solve();
return 0;
}
数据生成
#include<bits/stdc++.h>
using namespace std;
int random(int x)
{
return (rand()*rand()+rand())%x+1;
}
int main()
{
freopen("in.txt","w",stdout);
srand(time(0));
int n=random(10000),m=random(10000);
cout<<n<<" "<<m<<endl;
int t;
for(int i=1;i<=n;i++)
{
t=random(2);
if(t==2)t=-1;
cout<<random(10000000)*t<<" ";
}
cout<<endl;
for(int i=2;i<=n;i++)
cout<<i-1<<" "<<i<<endl;
int op;
for(int i=1;i<=m;i++)
{
op=random(2);
cout<<op<<" ";
cout<<random(n)<<" "<<random(n);
if(op==1)cout<<" "<<random(100000000)<<endl;
else
cout<<endl;
}
return 0;
}
暴力
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int maxn=1e5+100,oo=16;
int np,first[maxn];
struct edge{
int to,next;
}E[maxn<<1];
void add(int u,int v)
{
E[++np]=(edge){v,first[u]};
first[u]=np;
}
int n,m,fa[maxn][25],dep[maxn];
LL a[maxn];
void DFS(int i,int f,int d)
{
dep[i]=d;
fa[i][0]=f;
for(int j=1;j<=oo;j++)
fa[i][j]=fa[fa[i][j-1]][j-1];
for(int p=first[i];p;p=E[p].next)
{
int j=E[p].to;
if(j==f)continue;
DFS(j,i,d+1);
}
}
int LCA(int u,int v)
{
if(dep[u]<dep[v])swap(u,v);
int delt=dep[u]-dep[v];
for(int j=oo;j>=0;j--)
if(delt&(1<<j))u=fa[u][j];
if(u==v)return u;
for(int j=oo;j>=0;j--)
if(fa[u][j]!=fa[v][j])
u=fa[u][j],v=fa[v][j];
return fa[u][0];
}
void Init()
{
int u,v;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)cin>>a[i];
for(int i=1;i<n;i++)
{
scanf("%d%d",&u,&v);
add(u,v);
add(v,u);
}
DFS(1,0,1);
}
void modify(int u,int v,LL d)
{
int z=LCA(u,v);
for(int x=u;x!=z;x=fa[x][0])a[x]+=d;
for(int x=v;x!=z;x=fa[x][0])a[x]+=d;
a[z]+=d;
}
LL query(int u,int v)
{
LL ret=0;
int z=LCA(u,v);
for(int x=u;x!=z;x=fa[x][0])ret+=abs(a[x]);
for(int x=v;x!=z;x=fa[x][0])ret+=abs(a[x]);
ret+=abs(a[z]);
return ret;
}
void solve()
{
int op,u,v;
LL d;
for(int i=1;i<=m;i++)
{
scanf("%d%d%d",&op,&u,&v);
if(op==1)
{
cin>>d;
modify(u,v,d);
}
else
{
cout<<query(u,v)<<endl;
}
}
}
int main()
{
freopen("in.txt","r",stdin);
freopen("out2.txt","w",stdout);
Init();
solve();
return 0;
}
对拍
#include<bits/stdc++.h>
using namespace std;
int main()
{
for(int i=1;i<=1000;i++)
{
printf("正在运行数据:第%d组\n",i);
system("数据生成.exe");
cout<<"数据生成已完成"<<endl;
system("未命名1.exe");
system("未命名2.exe");
int e=system("fc /N out1.txt out2.txt");
if(e)
{
system("pause");
break;
}
}
return 0;
}