描述
校门外有很多树,有苹果树,香蕉树,有会扔石头的,有可以吃掉补充体力的……
如今学校决定在某个时刻在某一段种上一种树,保证任一时刻不会出现两段相同种类的树,现有两个操作:
K=1,K=1,读入l、r表示在区间[l,r]中种上一种树,每次操作种的树的种类都不同
K=2,读入l,r表示询问l~r之间能见到多少种树
(l,r>0)
格式
输入格式
第一行n,m表示道路总长为n,共有m个操作
接下来m行为m个操作
输出格式
对于每个k=2输出一个答案
样例1
样例输入1
5 4
1 1 3
2 2 5
1 2 4
2 3 5
样例输出1
1
2
限制
1s
提示
范围:20%的数据保证,n,m<=100
60%的数据保证,n <=1000,m<=50000
100%的数据保证,n,m<=50000
来源
dejiyu@CSC WorkGroup
这道题是典型的区间问题
但由于树的种类比较多,直接维护可能会超时
于是就用括号序列来做 。
比方说[2,10] 种树 在2 放一个左括号,10放一个右括号
统计[2,10]内有多少树的话,就找[2,10]内左括号的数量减去[1,2]内右括号的数量
#include <cstring> #include <cstdio> typedef long long LL; struct tree { LL l,r; LL zk,yk; }t[500000*4+1]; LL n,m,ans; void build(LL k,LL l,LL r) { t[k].l=l;t[k].r=r; if(l==r) return; LL mid=(l+r)>>1; build(k<<1,l,mid); build(k<<1|1,mid+1,r); } void ptz(LL l,LL k) { if(t[k].l==l&&t[k].r==l) t[k].zk++; else { LL mid=(t[k].l+t[k].r)>>1; if(l>mid) ptz(l,k<<1|1); else if(l<=mid) ptz(l,k<<1); t[k].zk=t[k<<1].zk+t[k<<1|1].zk; } } void pty(LL l,LL k) { if(t[k].l==l&&t[k].r==l) t[k].yk++; else { LL mid=(t[k].l+t[k].r)>>1; if(l>mid) pty(l,k<<1|1); else if(l<=mid) pty(l,k<<1); t[k].yk=t[k<<1].yk+t[k<<1|1].yk; } } LL queryz(LL l,LL r,LL k) { if(t[k].l>=l&&t[k].r<=r) return t[k].zk; LL mid=(t[k].l+t[k].r)>>1; if(r<=mid) return queryz(l,r,k<<1); else if(l>mid) return queryz(l,r,k<<1|1); else return queryz(l,mid,k<<1)+queryz(mid+1,r,k<<1|1); } LL queryy(LL l,LL r,LL k) { if(t[k].l>=l&&t[k].r<=r) return t[k].yk; LL mid=(t[k].l+t[k].r)>>1; if(r<=mid) return queryy(l,r,k<<1); else if(l>mid) return queryy(l,r,k<<1|1); else return queryy(l,mid,k<<1)+queryy(mid+1,r,k<<1|1); } void qr(LL &x) { x=0;bool f=0; char ch=getchar(); while(ch>'9'||ch<'0') { if(ch=='-') f=1; ch=getchar(); } while(ch>='0'&&ch<='9') { x=x*10+(int)ch-48; ch=getchar(); } x=(f==1)?((~x)+1):x; } int main() { qr(n);qr(m); build(1,1,n); for(LL x,y,z;m--;) { qr(x);qr(y);qr(z); if(x==1) ptz(y,1),pty(z,1); else { LL ans=queryz(1,z,1); if(y!=1) ans-=queryy(1,y-1,1); printf("%lld ",ans); } } return 0; }