BZOJ2752: [HAOI2012]高速公路(road)
题目:http://www.lydsy.com/JudgeOnline/problem.php?id=2752
首先以点代边,设第i个点表示i-1>i。
对于每个点算贡献,假设这个点是p,当前询问区间是[l,r],那么它的贡献为2*(p-l)*(r-p+1)*vp/((r-l)*(r-l+1)),打开合并同类项得到-(l+l*r)*vp+(l+r+1)*p*vp-p^2*vp
那么我们只要快速处理出区间的vp,p*vp,p^2*vp然后就可以用线段树维护了。
1^2+2^2+……+n^2=n*(n+1)*(2*n+1)/6
(写代码半个小时,打错一行代码调一晚上,真是太弱了TAT。。。由于我懒得不行于是所有变量都开LL,好像也不会特别慢嘛TAT
#include<cstring> #include<iostream> #include<cstdio> #include<algorithm> #define rep(i,l,r) for (int i=l;i<=r;i++) #define down(i,l,r) for (int i=l;i>=r;i--) #define clr(x,y) memset(x,y,sizeof(x)) #define maxn 100500 using namespace std; typedef long long ll; struct data{ll s[4],tag,size,l,r; }t[maxn*5]; ll n,m; ll ans,s; ll read(){ ll x=0,f=1; char ch=getchar(); while (!isdigit(ch)) { if (ch=='-') f=-1; ch=getchar(); } while (isdigit(ch)){ x=x*10+ch-'0'; ch=getchar(); } return x*f; } ll gcd(ll x,ll y){ if (y==0) return x; return gcd(y,x%y); } void print(ll ans,ll s){ ll k=gcd(ans,s); printf("%lld/%lld\n",ans/k,s/k); } void build(ll i,ll l,ll r){ t[i].l=l; t[i].r=r; t[i].tag=0; t[i].size=(r-l+1); if (l==r) return ; ll mid=(l+r)/2; build(i*2,l,mid); build(i*2+1,mid+1,r); } ll get(ll n){ return n*(n+1)*(2*n+1)/6; } void update(ll i,ll z){ t[i].tag+=z; t[i].s[1]+=t[i].size*z; t[i].s[2]+=t[i].size*(t[i].l+t[i].r)/2*z; t[i].s[3]+=(get(t[i].r)-get(t[i].l-1))*z; } void up(ll i){ rep(j,1,3) t[i].s[j]=t[i*2].s[j]+t[i*2+1].s[j]; } void Down(ll i){ update(i*2,t[i].tag); update(i*2+1,t[i].tag); t[i].tag=0; } void add(ll i,ll x,ll y,ll z){ ll l=t[i].l,r=t[i].r,mid=(l+r)/2; if (l==x&&r==y) { update(i,z); return; } if (t[i].tag) Down(i); if (x<=mid) add(i*2,x,min(mid,y),z); if (y>=mid+1) add(i*2+1,max(x,mid+1),y,z); up(i); } ll ask(ll i,ll x,ll y,ll k){ ll l=t[i].l,r=t[i].r,mid=(l+r)/2; ll ans=0; if (l==x&&y==r) return t[i].s[k]; if (t[i].tag) Down(i); if (x<=mid) ans+=ask(i*2,x,min(mid,y),k); if (y>=mid+1) ans+=ask(i*2+1,max(x,mid+1),y,k); return ans; } int main(){ n=read(); m=read(); build(1,1,n); rep(i,1,m){ ll x,y,l,r; ll z; char ch=getchar(); while (ch!='C'&&ch!='Q') ch=getchar(); if (ch=='C'){ x=read(); y=read(); scanf("%lld",&z); add(1,x+1,y,z); } else { l=read(); r=read(); ans=(-(l+l*r)*ask(1,l+1,r,1)+(l+r+1)*ask(1,l+1,r,2)-ask(1,l+1,r,3)); s=(r-l)*(r-l+1)/2; print(ans,s); } } return 0; }