题意:
给出一个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;
}