Description
Y901高速公路是一条重要的交通纽带,政府部门建设初期的投入以及使用期间的养护费用都不低,因此政府在这条高速公路上设立了许多收费站。
Y901高速公路是一条由N1段路以及N个收费站组成的东西向的链,我们按照由西向东的顺序将收费站依次编号为1N,从收费站i行驶到i+1(或从i+1行驶到i)需要收取Vi的费用。高速路刚建成时所有的路段都是免费的。
政府部门根据实际情况,会不定期地对连续路段的收费标准进行调整,根据政策涨价或降价。
无聊的小A同学总喜欢研究一些稀奇古怪的问题,他开车在这条高速路上行驶时想到了这样一个问题:对于给定的l,r(l<r),在第l个到第r个收费站里等概率随机取出两个不同的收费站ab,那么从a行驶到b将期望花费多少费用呢?

Input
第一行2个正整数N,M,表示有N个收费站,M次调整或询问
接下来M行,每行将出现以下两种形式中的一种:
C l r v 表示将第l个收费站到第r个收费站之间的所有道路的通行费全部增加v
Q l r 表示对于给定的l,r,要求回答小A的问题。
所有C与Q操作中保证1<=l<r<=N

Output
对于每次询问操作回答一行,输出一个既约分数。
若答案为整数a,输出a/1

Sample Input
4 5
C 1 4 2
C 1 2 -1
Q 1 2
Q 2 4
Q 1 4

Sample Output
1/1
8/3
17/6

HINT

数据规模
所有C操作中的v的绝对值不超过10000
在任何时刻任意道路的费用均为不超过10000的非负整数。
所有测试点的详细情况如下表所示:

Test N M
1 =10 =10
2 =100 =100
3 =1000 =1000
4 =10000 =10000
5 =50000 =50000
6 =60000 =60000
7 =70000 =70000
8 =80000 =80000
9 =90000 =90000
10 =100000 =100000

Source

思路
纯数学题啊……考虑一条道路i对答案的贡献(记为ansi),设这条道路的权值为vi,那么记

{vii=viiviii=vii2
ansi=vi[(il+1)(ri)]=vi(irlr+ri2+ili)=viirvilr+virviii+viilvii=vi(lr+r)+vii(l+r1)viii
则有
ans=i=lr1vi(lr+r)+i=lr1vii(l+r1)i=lr1viii
那么只要维护vi之和,vii之和,viii之和就可以了。而当将一些范围为lr的道路增加q,那么:
v+=q(rl+1)vi+=q(l+r)(rl+1)2vii+=qr(r+1)(2r+1)l(l+1)(2l+1)6
具体怎么证在这里就不讲了,自己去上网搜吧。

代码

#include <cstdio>

const int maxn=100000;

struct data
{
  long long v,vi,vii;

  data operator +=(const data &other)
  {
    v+=other.v;
    vi+=other.vi;
    vii+=other.vii;
    return *this;
  }

  data(long long vv=0,long long vvi=0,long long vvii=0):v(vv),vi(vvi),vii(vvii){}
};
struct segment_tree
{
  long long v[(maxn<<2)+10],vi[(maxn<<2)+10],vii[(maxn<<2)+10],lazy[(maxn<<2)+10];

  long long updata(long long now)
  {
    v[now]=v[now<<1]+v[now<<1|1];
    vi[now]=vi[now<<1]+vi[now<<1|1];
    vii[now]=vii[now<<1]+vii[now<<1|1];
    return 0;
  }

  long long push(long long now,long long left,long long right,long long q)
  {
    v[now]+=q*(right-left+1);
    vi[now]+=(q*(left+right)*(right-left+1))>>1;
    vii[now]+=q*(right*(right+1)*((right<<1)+1)-(left-1)*left*((left<<1)-1))/6;
    lazy[now]+=q;
    return 0;
  }

  long long pushdown(long long now,long long left,long long right)
  {
    if(lazy[now])
      {
        long long mid=(left+right)>>1;
        push(now<<1,left,mid,lazy[now]);
        push(now<<1|1,mid+1,right,lazy[now]);
        lazy[now]=0;
      }
    return 0;
  }

  long long build(long long now,long long left,long long right)
  {
    if(left==right)
      {
        lazy[now]=v[now]=vi[now]=vii[now]=0;
        return 0;
      }
    lazy[now]=v[now]=vi[now]=vii[now]=0;
    long long mid=(left+right)>>1;
    build(now<<1,left,mid);
    build(now<<1|1,mid+1,right);
    return 0;
  }

  long long add(long long now,long long left,long long right,long long askl,long long askr,long long cval)
  {
    if((askl<=left)&&(right<=askr))
      {
        push(now,left,right,cval);
        return 0;
      }
    long long mid=(left+right)>>1;
    pushdown(now,left,right);
    if(askl<=mid)
      {
        add(now<<1,left,mid,askl,askr,cval);
      }
    if(mid<askr)
      {
        add(now<<1|1,mid+1,right,askl,askr,cval);
      }
    updata(now);
    return 0;
  }

  data query(long long now,long long left,long long right,long long askl,long long askr)
  {
    if((askl<=left)&&(right<=askr))
      {
        return data(v[now],vi[now],vii[now]);
      }
    pushdown(now,left,right);
    long long mid=(left+right)>>1;
    data res=data();
    if(askl<=mid)
      {
        res+=query(now<<1,left,mid,askl,askr);
      }
    if(mid<askr)
      {
        res+=query(now<<1|1,mid+1,right,askl,askr);
      }
    return res;
  }
};

long long n,m,a,b,c;
char s[10];
segment_tree st;
data ans;

long long gcd(long long a,long long b)
{
  if(!b)
    {
      return a;
    }
  else
    {
      return gcd(b,a%b);
    }
}

int main()
{
  scanf("%lld%lld",&n,&m);
  --n;
  st.build(1,1,n);
  while(m--)
    {
      scanf("%s%I64d%I64d",s,&a,&b);
      if(s[0]=='C')
        {
          scanf("%lld",&c);
          st.add(1,1,n,a,b-1,c);
        }
      else
        {
          ans=st.query(1,1,n,a,b-1);
          long long t=ans.v*(-a*b+b)+ans.vi*(a+b-1)-ans.vii;
          if(!t)
            {
              puts("0/1");
            }
          else
            {
              long long m=((b-a)*(b-a+1))>>1,g=gcd(t,m);
              printf("%lld/%lld\n",t/g,m/g);
            }
        }
    }
  return 0;
}