以上三道题在洛谷都能找到。
总结一下就是,记录分治时的父亲。
因为是子树关系的,并不关心真实的父亲是谁,所以可以放在点分树上维护两个数组来计算信息。
本文代码量超长,请谨慎食用。
这道题是入门题,比较简单。幻想乡战略游戏传送门
//幻想乡战略游戏
#include<bits/stdc++.h>
using namespace std;
const int MAXN=4e5+5;
#define ll long long
ll n,m;
struct edge{
ll to,next,w;
}e[MAXN<<1];
struct mmap{
ll to,next,y;
}e2[MAXN<<1];
ll head2[MAXN],cnt2=0;
inline void add2(ll u,ll v,ll w){e2[++cnt2]=(mmap){v,head2[u],w},head2[u]=cnt2;}
ll head[MAXN],cnt=0;
inline void add(ll u,ll v,ll w){e[++cnt]=(edge){v,head[u],w},head[u]=cnt;}
ll fa[MAXN],hson[MAXN],size[MAXN],dep[MAXN],dis[MAXN];
void dfs1(ll u,ll father){
dep[u]=dep[father]+1;
size[u]=1;
fa[u]=father;
for(ll i=head[u];i;i=e[i].next){
ll v=e[i].to,w=e[i].w;
if(v==father)continue;
dis[v]=dis[u]+w;
dfs1(v,u);
size[u]+=size[v];
if(size[v]>size[hson[u]]||!hson[u])hson[u]=v;
}
}
ll id[MAXN],real1[MAXN],top[MAXN],num=0;
void dfs2(ll u,ll tp){
id[u]=++num;
top[u]=tp;
real1[num]=u;
if(hson[u])dfs2(hson[u],tp);
for(ll i=head[u];i;i=e[i].next){
ll v=e[i].to;
if(v==fa[u]||v==hson[u])continue;
dfs2(v,v);
}
}
inline ll chain_query(ll x,ll y){
ll tx=top[x],ty=top[y];
ll ans=0;
while(tx!=ty){//dep大的是在下面
if(dep[tx]>dep[ty]){
x=fa[tx];
}
else {
y=fa[ty];
}
tx=top[x],ty=top[y];
}
if(dep[x]>dep[y])swap(x,y);
return x;
}
inline ll get_dis(ll x,ll y){
return dis[x]+dis[y]-(dis[chain_query(x,y)]<<1);
}
struct dft{
ll sum,rt;
ll size[MAXN],f[MAXN],par[MAXN];
ll cost_subtree[MAXN],costfa_subtree[MAXN],dv[MAXN];//在点分树上维护这三个东西
bool vis[MAXN];
void getrt(ll u,ll fa){
size[u]=1;
f[u]=0;
for(ll i=head[u];i;i=e[i].next){
ll v=e[i].to;
if(v==fa||vis[v])continue;
getrt(v,u);
size[u]+=size[v];
f[u]=max(f[u],size[v]);
}
f[u]=max(f[u],sum-size[u]);
if(f[u]<f[rt])rt=u;
}
void solve(ll u,ll fa){
vis[u]=1;par[u]=fa;
for(ll i=head[u];i;i=e[i].next){
ll v=e[i].to;
if(vis[v])continue;
sum=f[0]=size[v];
getrt(v,rt=0);add2(u,rt,v);
solve(rt,u);
}
}
void change(ll u,ll val){
dv[u]+=val;
for(ll i=u;par[i];i=par[i]){
ll disnum=get_dis(u,par[i]);
cost_subtree[par[i]]+=disnum*val;
costfa_subtree[i]+=disnum*val;
dv[par[i]]+=val;
}
}
ll calc(ll u){
ll ans=cost_subtree[u];
for(ll i=u;par[i];i=par[i]){
ll disnum=get_dis(u,par[i]);
ans+=cost_subtree[par[i]]-costfa_subtree[i];
ans+=disnum*(dv[par[i]]-dv[i]);
}
return ans;
}
ll query(ll u){
ll ans=calc(u);
for(ll i=head2[u];i;i=e2[i].next){
ll v=e2[i].to,y=e2[i].y;
ll tem=calc(y);
if(tem<ans)return query(v);
}
return ans;
}
}dft;
int main(){
ll oldrt;
dft.rt=0;
memset(dft.vis,0,sizeof(dft.vis));
scanf("%lld%lld",&n,&m);
for(ll i=1;i<n;i++){
ll tem1,tem2,tem3;
scanf("%lld%lld%lld",&tem1,&tem2,&tem3);
add(tem1,tem2,tem3);add(tem2,tem1,tem3);
}
dft.sum=dft.f[0]=n;
dft.getrt(1,0);
oldrt=dft.rt;
dfs1(dft.rt,dft.rt);
dfs2(dft.rt,dft.rt);
dft.solve(dft.rt,0);
for(ll i=1;i<=m;i++){
ll tem1,tem2;
scanf("%lld%lld",&tem1,&tem2);
dft.change(tem1,tem2);
printf("%lld\n",dft.query(oldrt));
}
return 0;
}
开店传送门
这道题在做的时候还是很快想到前缀和去弄的。。主要是没想到用vector二分查找。
用vector去维护一个按点权的子树距离前缀和,查询的时候二分查找。代码里面有手写的upper_bound和lower_bond (我才不会说我不会用STL的呢)。
注意自己这个点也要放进去,然后重心别找错(getdis).
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const ll MAXN=4e5+5;
struct edge{
ll to,next;ll w;
}e[MAXN<<1];
struct data{
ll val,disn,sum;//点权
};
inline ll mymax(ll a,ll b){return a>b?a:b;}
inline ll mymin(ll a,ll b){return a>b?b:a;}
bool cmp(data a,data b){
if(a.val==b.val)return a.disn<b.disn;
return a.val<b.val;
}
vector<data>sub[MAXN],subfa[MAXN];
ll head[MAXN],cnt=0;
inline void add(ll u,ll v,ll w){e[++cnt]=(edge){v,head[u],w},head[u]=cnt;}
ll n,m,A,w[MAXN<<2];
ll size[MAXN],dep[MAXN],fa[MAXN],hson[MAXN];
ll dis[MAXN];
void dfs1(ll u,ll father){
size[u]=1;
dep[u]=dep[father]+1;
fa[u]=father;
for(ll i=head[u];i;i=e[i].next){
ll v=e[i].to,w=e[i].w;
if(v==father)continue;
dis[v]=dis[u]+w;
dfs1(v,u);
size[u]+=size[v];
if(size[v]>size[hson[u]])hson[u]=v;
}
}
ll top[MAXN];
void dfs2(ll u,ll tp){
top[u]=tp;
if(hson[u])dfs2(hson[u],tp);
for(ll i=head[u];i;i=e[i].next){
ll v=e[i].to;
if(v==fa[u]||v==hson[u])continue;
dfs2(v,v);
}
}
inline ll lca(ll x,ll y){
ll tx=top[x],ty=top[y];
while(tx!=ty){
if(dep[tx]>dep[ty])
x=fa[tx];
else y=fa[ty];
tx=top[x],ty=top[y];
}
if(dep[x]>dep[y])swap(x,y);
return x;
}
ll par[MAXN],rt=0,sum=0,Size[MAXN],f[MAXN];
bool vis[MAXN];
void getrt(ll u,ll fa){
Size[u]=1;
f[u]=0;
for(ll i=head[u];i;i=e[i].next){
ll v=e[i].to;
if(vis[v]||v==fa)continue;
getrt(v,u);
Size[u]+=Size[v];
f[u]=max(f[u],Size[v]);
}
f[u]=max(f[u],sum-Size[u]);
if(f[u]<f[rt])rt=u;
}
void get(ll u,ll fa){
Size[u]=1;
f[u]=0;
for(ll i=head[u];i;i=e[i].next){
ll v=e[i].to;
if(vis[v]||v==fa)continue;
getrt(v,u);
Size[u]+=Size[v];
f[u]=max(f[u],Size[v]);
}
f[u]=max(f[u],sum-Size[u]);
if(f[u]<f[rt])rt=u;
}
void solve(ll u,ll fa){
vis[u]=1;par[u]=fa;//cout<<par[u]<<"ok1"<<endl;
for(ll i=head[u];i;i=e[i].next){
ll v=e[i].to;
if(vis[v])continue;
get(v,0);
sum=f[0]=Size[v];
getrt(v,rt=0);
solve(rt,u);
}
}
inline ll getdis(ll x,ll y){
return dis[x]+dis[y]-(dis[lca(x,y)]<<1);
}
// l 大等于中最小的-1 lower-1
//r 严格大于最小的-1 upper-1
ll lower(ll u,ll sz,ll vv){
ll l=0,r=sz-1;
while(l+1<r){
ll mid=(l+r)>>1;
if(sub[u][mid].val>=vv)r=mid;
else l=mid;
}
return r;
}
ll upper(ll u,ll sz,ll vv){
ll l=0,r=sz-1;
while(l+1<r){
ll mid=(l+r)>>1;
if(sub[u][mid].val>vv)r=mid;
else l=mid;
}
return r;
}
ll lowerfa(ll u,ll sz,ll vv){
ll l=0,r=sz-1;
while(l+1<r){
ll mid=(l+r)>>1;
if(subfa[u][mid].val>=vv)r=mid;
else l=mid;
}
return r;
}
ll upperfa(ll u,ll sz,ll vv){
ll l=0,r=sz-1;
while(l+1<r){
ll mid=(l+r)>>1;
if(subfa[u][mid].val>vv)r=mid;
else l=mid;
}
return r;
}
inline ll queryr(ll u,ll v){
ll ans=0;
ll N=upper(u,sub[u].size(),v)-1;
ans=sub[u][N].sum;
for(ll i=u;par[i];i=par[i]){
ll dist=getdis(u,par[i]);
ll NF=upperfa(i,subfa[i].size(),v)-1;
ll ND=upper(par[i],sub[par[i]].size(),v)-1;
ans+=sub[par[i]][ND].sum-subfa[i][NF].sum;
ans+=dist*(ND-NF);
}
return ans;
}
inline ll queryl(ll u,ll v){
ll ans=0;
ll N=lower(u,sub[u].size(),v)-1;
ans=sub[u][N].sum;
for(ll i=u;par[i];i=par[i]){
ll dist=getdis(u,par[i]);
ll NF=lowerfa(i,subfa[i].size(),v)-1;
ll ND=lower(par[i],sub[par[i]].size(),v)-1;
ans+=sub[par[i]][ND].sum-subfa[i][NF].sum;
ans+=dist*(ND-NF);
}
return ans;
}
int main(){
memset(vis,0,sizeof(vis));
ll oldrt;
scanf("%lld%lld%lld",&n,&m,&A);
for(ll i=1;i<=n;i++){
scanf("%lld",&w[i]);
}
for(ll i=1;i<n;i++){
ll tem1,tem2,tem3;
scanf("%lld%lld%lld",&tem1,&tem2,&tem3);
add(tem1,tem2,tem3);add(tem2,tem1,tem3);
// cout<<"!!!"<<tem1<<":::"<<tem2<<endl;
}
sum=f[0]=n;
getrt(1,rt=0);
oldrt=rt;
solve(rt,0);
dfs1(oldrt,oldrt);
dfs2(oldrt,oldrt);
for(ll i=1;i<=n;i++){//维护节点信息,某个点权到当前点的距离。
sub[i].push_back((data){w[i],0,0});
for(ll j=i;par[j];j=par[j]){
ll disnum=getdis(par[j],i);
sub[par[j]].push_back((data){w[i],disnum,0});
subfa[j].push_back((data){w[i],disnum,0});
}
}
for(ll i=1;i<=n;i++){
sub[i].push_back((data){-1,0,0});sub[i].push_back((data){1<<30,0,0});
subfa[i].push_back((data){-1,0,0});subfa[i].push_back((data){1<<30,0,0});
sort(sub[i].begin(),sub[i].end(),cmp);
sort(subfa[i].begin(),subfa[i].end(),cmp);
for(ll j=1;j<sub[i].size();j++)sub[i][j].sum=sub[i][j-1].sum+sub[i][j].disn;
for(ll j=1;j<subfa[i].size();j++)subfa[i][j].sum=subfa[i][j-1].sum+subfa[i][j].disn;
}
ll ans=0;
for(ll i=1;i<=m;i++){
ll tem1,tem2;ll tem3;
scanf("%lld%lld%lld",&tem3,&tem1,&tem2);
ll l=mymin((ans+tem1)%A,(ans+tem2)%A);
ll r=mymax((ans+tem1)%A,(ans+tem2)%A);
ans=queryr(tem3,r)-queryl(tem3,l);
printf("%lld\n",ans);
}
return 0;
}
这道题详细的解释见洛谷zzq神犇的题解。这题比较灵性的就是线段树那里吧,好好思考一下,我放代码跑。
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const ll MAXN=4e5+5;
ll n,q,w[MAXN];
ll esum=0,ww[MAXN];
struct edge{
ll to,next,w;
}e[MAXN<<1];
ll head[MAXN],cnt=0;
inline void add(ll u,ll v,ll w){
e[++cnt]=(edge){v,head[u],w},head[u]=cnt;
e[++cnt]=(edge){u,head[v],w},head[v]=cnt;
}
ll fa[MAXN],size[MAXN],hson[MAXN],dep[MAXN],dis[MAXN];
void dfs1(ll u,ll father){
dep[u]=dep[father]+1;
fa[u]=father;
size[u]=1;
for(ll i=head[u];i;i=e[i].next){
ll v=e[i].to,w=e[i].w;
if(v==father)continue;
dis[v]=dis[u]+w;
dfs1(v,u);
size[u]+=size[v];
if(size[v]>size[hson[u]]||!hson[u])hson[u]=v;
}
}
ll top[MAXN];
void dfs2(ll u,ll tp){
top[u]=tp;
if(hson[u])dfs2(hson[u],tp);
for(ll i=head[u];i;i=e[i].next){
ll v=e[i].to;
if(v==fa[u]||v==hson[u])continue;
dfs2(v,v);
}
}
inline ll lca(ll x,ll y){
ll tx=top[x],ty=top[y];
while(tx!=ty){
if(dep[tx]>dep[ty]) x=fa[tx];
else y=fa[ty];
tx=top[x],ty=top[y];
}
if(dep[x]>dep[y])swap(x,y);
return x;
}
ll rsize[MAXN],f[MAXN],sum,rt,par[MAXN],sub[MAXN],subfa[MAXN];
ll sumw[MAXN],sumwfa[MAXN];
bool vis[MAXN];
void getrt(ll u,ll fa){
rsize[u]=1;
f[u]=0;
for(ll i=head[u];i;i=e[i].next){
ll v=e[i].to,w=e[i].w;
if(v==fa||vis[v])continue;
getrt(v,u);
rsize[u]+=rsize[v];
f[u]=max(f[u],rsize[v]);
}
if(f[u]<sum-rsize[u])f[u]=sum-rsize[u];
if(f[u]<f[rt])rt=u;
}
void getsz(ll u,ll fa){
rsize[u]=1;
for(ll i=head[u];i;i=e[i].next){
ll v=e[i].to;
if(v==fa||vis[v])continue;
getrt(v,u);
rsize[u]+=rsize[v];
}
}
void solve(ll u,ll fa){
vis[u]=1;par[u]=fa;
for(ll i=head[u];i;i=e[i].next){
ll v=e[i].to;
if(v==fa||vis[v])continue;
getsz(v,0);
f[0]=sum=rsize[v];
getrt(v,rt=0);
solve(rt,u);
}
}
inline ll getdis(ll x,ll y){
return dis[x]+dis[y]-(dis[lca(x,y)]<<1);
}
void memfz(){//sub为cost
for(ll u=1;u<=n;u++){
sumw[u]+=w[u];
for(ll i=u;par[i];i=par[i]){
ll dist=getdis(u,par[i]);
sumw[par[i]]+=w[u];
sumwfa[i]+=w[u];
sub[par[i]]+=dist*w[u];
subfa[i]+=dist*w[u];
}
}
}
ll calc(ll u){
ll ans=sub[u];
for(ll i=u;par[i];i=par[i]){
ll dist=getdis(par[i],u);
ans+=sub[par[i]]-subfa[i];
ans+=dist*(sumw[par[i]]-sumwfa[i]);
}
return ans+esum;
}
struct rt1tree{
#define lson (o<<1)
#define rson (o<<1|1)
ll size[MAXN],dep[MAXN],fa[MAXN],hson[MAXN];
void dfs1(ll u,ll father){
size[u]=1;
dep[u]=dep[father]+1;
fa[u]=father;
for(ll i=head[u];i;i=e[i].next){
ll v=e[i].to;
if(v==father)continue;
dfs1(v,u);
ww[u]+=ww[v];
size[u]+=size[v];
if(!hson[u]||size[v]>size[hson[u]])hson[u]=v;
}
}
ll id[MAXN],top[MAXN],real1[MAXN];
ll num;
void dfs2(ll u,ll tp){
top[u]=tp;
id[u]=++num;
real1[num]=u;
if(hson[u])dfs2(hson[u],tp);
for(ll i=head[u];i;i=e[i].next){
ll v=e[i].to;
if(v==fa[u]||v==hson[u])continue;
dfs2(v,v);
}
}
ll sumv[MAXN<<2],lzt[MAXN<<2];
inline void pushdown(ll o,ll l,ll r){
if(lzt[o]){
ll mid=(l+r)>>1;
lzt[lson]+=lzt[o];sumv[lson]+=(mid-l+1)*lzt[o];
lzt[rson]+=lzt[o];sumv[rson]+=(r-mid)*lzt[o];
lzt[o]=0;
}
}
inline void pushup(ll o){sumv[o]=sumv[lson]+sumv[rson];}
void build(ll o,ll l,ll r){
lzt[o]=0;
if(l==r){sumv[o]=ww[real1[l]];return;}
ll mid=(l+r)>>1;
build(lson,l,mid);
build(rson,mid+1,r);
pushup(o);
}
void change(ll o,ll l,ll r,ll ql,ll qr,ll w){
if(ql<=l&&qr>=r){sumv[o]+=(r-l+1)*w;lzt[o]+=w;return;}
ll mid=(l+r)>>1;
pushdown(o,l,r);
if(ql<=mid)change(lson,l,mid,ql,qr,w);
if(qr>mid)change(rson,mid+1,r,ql,qr,w);
pushup(o);
}
ll query(ll o,ll l,ll r,ll ql,ll qr){
if(ql<=l&&qr>=r){return sumv[o];}
ll mid=(l+r)>>1,ans=0;
pushdown(o,l,r);
if(ql<=mid)ans+=query(lson,l,mid,ql,qr);
if(qr>mid)ans+=query(rson,mid+1,r,ql,qr);
return ans;
}
inline void chain_change(ll x,ll y,ll w){
ll tx=top[x],ty=top[y];
while(tx!=ty){
if(dep[tx]>dep[ty]){
change(1,1,n,id[tx],id[x],w);
x=fa[tx];
}
else {
change(1,1,n,id[ty],id[y],w);
y=fa[ty];
}
tx=top[x],ty=top[y];
}
if(dep[x]<dep[y])swap(x,y);
change(1,1,n,id[y],id[x],w);
}
inline ll chain_query(ll x,ll y){
ll tx=top[x],ty=top[y];
ll ans=0;
while(tx!=ty){
if(dep[tx]>dep[ty]){
ans+=query(1,1,n,id[tx],id[x]);
x=fa[tx];
}
else {
ans+=query(1,1,n,id[ty],id[y]);
y=fa[ty];
}
tx=top[x],ty=top[y];
}
if(dep[x]<dep[y])swap(x,y);
ans+=query(1,1,n,id[y],id[x]);
return ans;
}
inline ll querysub(ll p){
return query(1,1,n,id[p],id[p]+size[p]-1);
}
}T;
inline void dianfen_change(ll p,ll q){
sumw[p]+=q;
for(ll i=p;par[i];i=par[i]){
ll dist=getdis(p,par[i]);
ll cost=q*dist;
sumw[par[i]]+=q;
sumwfa[i]+=q;
sub[par[i]]+=cost;
subfa[i]+=cost;
}
}
int main(){
ll oldrt,wfang=0;
T.num=0;
memset(vis,0,sizeof(vis));
scanf("%lld%lld",&n,&q);
for(ll i=1;i<n;i++){
ll tem1,tem2;
scanf("%lld%lld",&tem1,&tem2);
add(tem1,tem2,1);
}
for(ll i=1;i<=n;i++){
scanf("%lld",&w[i]);
ww[i]=w[i];
esum+=w[i];
}
sum=f[0]=n;
getrt(1,rt=0);
oldrt=rt;
solve(rt,0);
dfs1(oldrt,oldrt);
dfs2(oldrt,oldrt);
memfz();
T.dfs1(1,1);
T.dfs2(1,1);
T.build(1,1,n);
for(ll i=1;i<=n;i++)wfang+=T.chain_query(i,i)*T.chain_query(i,i);
for(ll i=1;i<=q;i++){
ll tem1,tem2,tem3;
scanf("%lld%lld",&tem1,&tem2);
if(tem1==1){
scanf("%lld",&tem3);
ll q=tem3-w[tem2];
esum+=q;
w[tem2]=tem3;
ll p=T.chain_query(1,tem2);
wfang+=((p*q)<<1)+(getdis(1,tem2)+1)*q*q;
T.chain_change(1,tem2,q);
dianfen_change(tem2,q);
}
else {
ll g=calc(1);
g*=esum;
g-=wfang;
ll ww=calc(tem2);
ww*=esum;
ww-=g;
printf("%lld\n",ww);
}
}
return 0;
}