线段树区间开方、区间求和
不过这个好像有点问题,就是在update那个函数里,有一个小的剪枝,就是当 t[p].sum==t[p].r-t[p].l+1 时,直接return,我感觉这里是错的,因为如果这个区间里有一个值为0,还有一个值为2,其他值全是0,这个地方就不能这样了。如果题目保证输入点权都是大于0的就可以了,但题目并没有保证。如果不加这个剪枝的话会T,加上的话应该会WA,但是AC了,应该是因为题目后面没有点权为0的数据吧......
ACcode:
#include<bits/stdc++.h>
#define de cout<<endl<<endl<<endl
typedef long long ll;
const ll N=2e5+10;
using namespace std;
ll n,q,r;
ll a[N<<2];
ll tot,ver[N<<1],Next[N<<1],head[N<<1];
void add(ll x,ll y)
{
ver[++tot]=y;Next[tot]=head[x];head[x]=tot;
}
//以下是线段树******************************************************************
struct stree
{
ll l,r;
ll sum,add;
} t[N<<2];
void build(ll p,ll l,ll r) //建树 build(1,1,n)
{
t[p].l=l,t[p].r=r;
if(l==r)
{
t[p].sum=a[l];
return ;
}
ll mid=(l+r)/2;
build(p*2,l,mid);
build(p*2+1,mid+1,r);
t[p].sum=t[p*2].sum+t[p*2+1].sum;
}
void update(ll p,ll l,ll r)
{
if(t[p].sum==t[p].r-t[p].l+1)
return ;
//上面这一句有点小问题,比如当这个区间的点权为 0 2 1 1 1 1 ......
if(t[p].l==t[p].r)
{
t[p].sum=sqrt(t[p].sum);
return ;
}
ll mid=(t[p].l+t[p].r)>>1;
if(l<=mid) update(p*2,l,r);
if(r>mid) update(p*2+1,l,r);
t[p].sum=t[p*2].sum+t[p*2+1].sum;
}
//第l到r个数的和,调用入口:query(1,l,r)
ll query(ll p,ll l,ll r)
{
if(l<=t[p].l&&r>=t[p].r)
return t[p].sum;
ll mid=(t[p].l+t[p].r)/2;
ll val=0;
if(l<=mid)
val=val+query(p*2,l,r);
if(r>mid)
val=val+query(p*2+1,l,r);
return val;
}
//以上是线段树*********************************************************************
int main()
{
ll TT=0;
while(scanf("%lld",&n)!=EOF)
{
tot=0;
r=1;
for(ll i=1;i<=n;i++) scanf("%lld",&a[i]);
build(1,1,n);
ll ans;
scanf("%lld",&q);
printf("Case #%lld:\n",++TT);
while(q--)
{
ll op,x,y;
scanf("%lld%lld%lld",&op,&x,&y);
if(x>y)
swap(x,y);
if(op==0)
update(1,x,y);
else
{
ans=query(1,x,y);
printf("%lld\n",ans);
}
}
printf("\n");
}
return 0;
}
树链刨分+线段树区间开方区间求和
ACcode:
#include<bits/stdc++.h>
#define de cout<<endl<<endl<<endl
typedef long long ll;
const ll N=2e5+10;
using namespace std;
ll n,q,r;
ll a[N<<2],b[N<<2];
ll tot,ver[N<<1],Next[N<<1],head[N<<1];
ll dep[N],fa[N],Size[N],son[N];
ll cnt,id[N],top[N];
/*
b[i] 初始节点的权值
a[i] 新建节点的权值
题目输入的是b[i],线段树中用的是a[i]
dep[i] 该节点的深度
fa[i] 该节点的父亲
Size[i] 该非叶子节点的子树大小
son[i] i的重儿子
cnt 新建节点时用来存编号的
id[i] 该节点的新编号
top[i] 该节点所在链的顶端节点编号
*/
void add(ll x,ll y)
{
ver[++tot]=y;Next[tot]=head[x];head[x]=tot;
}
void dfs1(ll x,ll f,ll deep) //当前节点 父亲 深度
{
dep[x]=deep;
fa[x]=f;
Size[x]=1;
ll maxson=-1;
for(ll i=head[x];i;i=Next[i])
{
ll y=ver[i];
if(y==f) continue;
dfs1(y,x,deep+1);
Size[x]+=Size[y];
if(Size[y]>maxson)
son[x]=y,maxson=Size[y];
}
}
void dfs2(ll x,ll topf) //当前节点 当前链的最顶端的节点
{
id[x]=++cnt;
a[cnt]=b[x];
top[x]=topf;
if(son[x]==0) return ;
dfs2(son[x],topf);
for(ll i=head[x];i;i=Next[i])
{
ll y=ver[i];
if(y==fa[x]||y==son[x]) continue;
dfs2(y,y);
}
}
//以下是线段树******************************************************************
struct stree
{
ll l,r;
ll sum,add;
} t[N<<2];
void build(ll p,ll l,ll r) //建树 build(1,1,n)
{
t[p].l=l,t[p].r=r;
if(l==r)
{
t[p].sum=a[l];
return ;
}
ll mid=(l+r)/2;
build(p*2,l,mid);
build(p*2+1,mid+1,r);
t[p].sum=t[p*2].sum+t[p*2+1].sum;
}
void update(ll p,ll l,ll r)
{
if(t[p].l==t[p].r)
{
t[p].sum=sqrt(t[p].sum);
return ;
}
ll mid=(t[p].l+t[p].r)>>1;
if(l<=mid) update(p*2,l,r);
if(r>mid) update(p*2+1,l,r);
t[p].sum=t[p*2].sum+t[p*2+1].sum;
}
//第l到r个数的和,调用入口:query(1,l,r)
ll query(ll p,ll l,ll r)
{
if(l<=t[p].l&&r>=t[p].r)
return t[p].sum;
//spread(p);
ll mid=(t[p].l+t[p].r)/2;
ll val=0;
if(l<=mid)
val=val+query(p*2,l,r);
if(r>mid)
val=val+query(p*2+1,l,r);
return val;
}
//以上是线段树*********************************************************************
void update1(ll x,ll y) //给节点x到节点y这条链上的所有节点都加上z
{
while(top[x]!=top[y])
{
if(dep[top[x]]<dep[top[y]]) swap(x,y);
update(1,id[top[x]],id[x]);
x=fa[top[x]];
}
if(dep[x]>dep[y]) swap(x,y);
update(1,id[x],id[y]);
}
ll query1(ll x,ll y) //询问节点x到节点y这条链上的所有节点的和
{
ll ret=0,res;
while(top[x]!=top[y])
{
if(dep[top[x]]<dep[top[y]]) swap(x,y);
res=query(1,id[top[x]],id[x]);
ret+=res;
x=fa[top[x]];
}
if(dep[x]>dep[y]) swap(x,y);
ret+=query(1,id[x],id[y]);
return ret;
}
int main()
{
tot=0;
cnt=0;
memset(a,0,sizeof a);
scanf("%lld%lld",&n,&q);
r=1;
for(ll i=1;i<=n;i++) scanf("%lld",&b[i]);
ll x,y;
for(ll i=1;i<=n-1;i++)
{scanf("%lld%lld",&x,&y);add(x,y);add(y,x);}
dfs1(r,0,1);
dfs2(r,r);
build(1,1,n);
ll ans;
while(q--)
{
ll op,x,y;
scanf("%lld%lld%lld",&op,&x,&y);
if(op==0)
update1(x,y);
else
{
ans=query1(x,y);
printf("%lld\n",ans);
}
}
return 0;
}