HDU6183 Color it 动态开点线段树
网址:https://vjudge.net/problem/HDU-6183
题意:
给出以下操作:$“0”$代表清空所有颜色,$"1$ $x$ $y$ $c$$"$代表在坐标$(x,y)$涂上第$c$种颜色,$"2$ $x$ $y_1$ $y_2$$"$代表统计$x$轴上$[1,x]$和y轴上$[y_1,y_2]$的颜色数,一个点可以有多种颜色,$“3”$代表结束。数据保证$n,m \leq 1e6,0 \geq c \leq 50,y_1 \leq y_2$。
题解:
别问,问就开50棵线段树(MLE警告),开$50$棵动态开点的线段树,以$y$轴为结点,维护区间内的颜色的最小的横坐标值。查询时,横坐标的区间左边界已经确定,区间右边界为$x$,则小于等于$x$的才会被统计,则区间中的最小横坐标值决定该区间是否有颜色满足要求,然后依次查询$50$种颜色即可。(本题需要剪枝,如果在左子树搜到了,就不需要在右子树搜索,否则会TLE)。
AC代码:
#include <bits/stdc++.h> #pragma GCC optimize(3) using namespace std; const int MAXN=1000005; const int M=0x3f3f3f3f; struct segtree { struct node { int l,r,ls,rs,sum,minn; /*node() { l=r=ls=rs=sum=0; minn=M; }*/ }; node tr[MAXN*3]; int rt[51]; int tot=0; inline void init() { memset(rt,0,sizeof(rt)); for(int i=0;i<MAXN*3;++i) tr[i].l=tr[i].r=tr[i].ls=tr[i].rs=tr[i].sum=0,tr[i].minn=M; tot=0; } inline void update(int &rt,int l,int r,int pos,int val) { if(!rt) rt=++tot; ++tr[rt].sum; tr[rt].l=l; tr[rt].r=r; tr[rt].minn=min(tr[rt].minn,val); if(l==r) return; int m=(l+r)>>1; if(pos<=m) update(tr[rt].ls,l,m,pos,val); else update(tr[rt].rs,m+1,r,pos,val); tr[rt].sum=tr[tr[rt].ls].sum+tr[tr[rt].rs].sum; } inline bool query(int l,int r,int rt,int lim) { if(!rt) return false; if(l<=tr[rt].l&&tr[rt].r<=r) { if(tr[rt].minn<=lim&&tr[rt].sum) return true; else return false; } int ans=0; int m=(tr[rt].l+tr[rt].r)>>1; if(l<=m&&!ans) ans+=query(l,r,tr[rt].ls,lim); if(r>m&&!ans) ans+=query(l,r,tr[rt].rs,lim); return ans; } }; segtree tr; int main() { int a,b,c,d; while(scanf("%d",&a)&&a!=3) { if(a==0) tr.init(); else if(a==1) { scanf("%d%d%d",&b,&c,&d); tr.update(tr.rt[d],1,1000000,c,b); } else if(a==2) { int ans=0; scanf("%d%d%d",&b,&c,&d); for(int i=0;i<=50;++i) ans+=tr.query(c,d,tr.rt[i],b); printf("%d\n",ans); } } return 0; }