题意:
给出一个n个结点,n-1条边的链,边权初始为0;
m次操作,操作有两种:
1. C:区间[l,r]的边权加上或减去一个数;
2. Q:查询区间随机取不相同两点之间的期望长度;
题解:
区间加减之类的东西显然是线段树的应用,恰巧这道题就在链上;
主要这题还是维护第二问的东西;
区间[l,r]的选路方式共有(r-l+1)*(r-l)/2这些种,那么只要求出所有路径总长度就好了;
对每一条路x来考虑的话,这条路被选的条件是同时选了左面的点和右面的点;
假设这条路的权值是val[x],那么这条路对答案的贡献就是 左面点数*右面点数*val[x];
问题在于如何用线段树实现对此的向上/向下更新;
向下更新的话,长度为n的区间所有数同时减去一个v的话,答案会变化 v*n(n+1)(n+2)/6 这个值;
其实就是1*4+2*3+3*2+4*1这东西的求和公式= =
而向上更新则是两个区间的合并,对每条路考虑左右增加的点数;
那左区间所有路其实都是在右面增加了 右面路径数 这样多的点;
对答案的影响就是 1*val[1]+2*val[2]+3*val[3]... 再乘一个点数;
那么设这东西为L,利用区间和也可以快速维护这东西;
右区间同理,维护R处理就可以了;
query函数有些糟糕,因为需要向上传四个参数,还要搞一个合并;
然后我比较懒所以直接用pair乱搞。。那段区间合并看着就蛮高能的。。
long long没开够WA了一发,全改成long long就A了;
具体原因不查了= =反正这东西似乎不重要?
代码:
#include<stdio.h> #include<string.h> #include<algorithm> #define N 140142 #define pr pair<ll,ll> #define par pair<pr,pr> #define lson l,mid,no<<1 #define rson mid+1,r,no<<1|1 using namespace std; typedef long long ll; ll sum[N<<2],ans[N<<2],L[N<<2],R[N<<2],cov[N<<2]; char str[10]; ll gcd(ll a,ll b) { ll t=a%b; while(t) { a=b,b=t; t=a%b; } return b; } void Pushup(ll no,ll len) { sum[no]=sum[no<<1]+sum[no<<1|1]; L[no]=L[no<<1]+L[no<<1|1]+sum[no<<1|1]*(len-(len>>1)); R[no]=R[no<<1]+R[no<<1|1]+sum[no<<1]*(len>>1); ans[no]=ans[no<<1]+ans[no<<1|1]+L[no<<1]*(len>>1)+R[no<<1|1]*(len-(len>>1)); } void change(ll no,ll v,ll n) { cov[no]+=v; sum[no]+=v*n; L[no]+=n*(n+1)/2*v; R[no]+=n*(n+1)/2*v; ans[no]+=n*(n+1)*(n+2)/6*v; } void Pushdown(ll no,ll len) { if(cov[no]) { change(no<<1,cov[no],len-(len>>1)); change(no<<1|1,cov[no],len>>1); cov[no]=0; } } void update(ll l,ll r,ll no,ll st,ll en,ll val) { if(st<=l&&r<=en) change(no,val,r-l+1); else { ll mid=l+r>>1; Pushdown(no,r-l+1); if(en<=mid) update(lson,st,en,val); else if(st>mid) update(rson,st,en,val); else update(lson,st,en,val),update(rson,st,en,val); Pushup(no,r-l+1); } } par query(ll l,ll r,ll no,ll st,ll en) { if(st<=l&&r<=en) return par(pr(ans[no],sum[no]),pr(L[no],R[no])); else { ll mid=l+r>>1; Pushdown(no,r-l+1); if(en<=mid) return query(lson,st,en); else if(st>mid) return query(rson,st,en); else { ll llen=(st<=l?r-l+1-((r-l+1)>>1):mid-st+1), rlen=(en>=r?(r-l+1)>>1:en-mid); par lp=query(lson,st,en),rp=query(rson,st,en),ret; ret.first.first=lp.first.first+lp.second.first*rlen+rp.first.first+rp.second.second*llen; ret.first.second=lp.first.second+rp.first.second; ret.second.first=lp.second.first+rp.second.first+rp.first.second*llen; ret.second.second=lp.second.second+rp.second.second+lp.first.second*rlen; return ret; } } } int main() { ll n,m,i,j,k,l,r; ll v,u,d,g; scanf("%lld%lld",&n,&m); n--; for(i=1;i<=m;i++) { scanf("%s",&str); if(str[0]=='C') { scanf("%lld%lld%lld",&l,&r,&v); update(1,n,1,l,r-1,v); } else { scanf("%lld%lld",&l,&r); u=query(1,n,1,l,r-1).first.first; d=(r-l+1)*(r-l)/2; g=gcd(u,d); printf("%lld/%lld\n",u/g,d/g); } } return 0; }
时间: 2024-10-10 16:27:57