HDU

B - Color itHDU - 6183 

  题目大意:有三种操作,0是清空所有点,1是给点(x,y)涂上颜色c,2是查询满足1<=a<=x,y1<=b<=y2的(a,b)点一共有几种不同的颜色

  一开始做的时候直接就是开51个vector保存每个颜色相应的点,然后就是询问就是,暴力循环判断这个颜色存不存在一个满足条件的点,感觉最差情况下应该会超时,不过却过了

 1 #include<cstdio>
 2 #include<vector>
 3 using namespace std;
 4 struct Node{
 5     int x,y;
 6     Node(){}
 7     Node(int x,int y):x(x),y(y){}
 8 };
 9 vector<Node> c[58];
10 int main()
11 {
12     int op,x,y,y1,cc;
13     while(scanf("%d",&op)&&op!=3)
14     {
15         if(op==0)
16         {
17             for(int i=0;i<=50;i++)
18                 c[i].clear();
19         }
20         else if(op==1)
21         {
22             scanf("%d%d%d",&x,&y,&cc);
23             c[cc].push_back(Node(x,y)); 
24         }
25         else
26         {
27             scanf("%d%d%d",&x,&y,&y1);
28             int ans=0;
29             for(int i=0;i<=50;i++)
30             {
31                 for(int j=0;j<c[i].size();j++)
32                     if(c[i][j].x<=x&&c[i][j].y>=y&&c[i][j].y<=y1)
33                     {
34                         ans++;
35                         break;
36                     }
37             }
38             printf("%d
",ans);
39         }
40     }
41     return 0;
42 }
暴力过一切

  然后看网上有是线段树动态开点的做法,但实际上并不比上面暴力的写法快,反而慢上几十ms,不过可以当做一个算法扩展来联系。

  首先1操作肯定就是单点更新了,而2操作上已经限定了x的左边为1,所以我们以y轴来建线段树维护个区间内x的最小值,那么2操作就是区间查询了。但我们知道正常静态的线段树需要4*SIZE的节点空间来保存信息的,在这里又需要51颗线段树,也就是51*4*1000000的空间来保存节点信息,不知道你们电脑能不能开那么大的数组,反正我的电脑和OJ的虚拟机是不行的。但其实最多150000个1操作和2操作,并不需要那么大的空间。所以这时候需要用到线段树的动态开点了。

  静态的线段树,每个编号为x的节点,它的左孩子编号就为2*x,右孩子编号就为2*x+1,然后这个节点x,我们是保存它的区间L,R和其他一系列信息。而动态开点的话,对于编号为x的节点,它的左右孩子的编号就不一定是2*x和2*x+1的关系了,所以我们要保存下的是它的左右孩子的编号已经一系列相关的信息,然后对于每个节点就是当需要到它时再开辟它。其他操作就和静态的线段树差不多。

 1 #include<cstdio>
 2 #include<algorithm>
 3 using namespace std;
 4 const int N=1001108;
 5 struct Tree{
 6     int lson,rson,minx;    
 7 }T[N];
 8 int tn,flag,root[52];
 9 //root就保存这个颜色对于的那棵线段树的根节点编号 
10 void init()
11 {
12     tn=1;
13     for(int i=0;i<=50;i++)
14         root[i]=0;
15 }
16 void updata(int &id,int L,int R,int y,int x)//在这里用L,R来表示节点id的区间 
17 {
18     if(!id)
19     {//需要到这个节点了,开辟这个节点 
20         id=tn++;
21         T[id].minx=N;
22         T[id].lson=T[id].rson=0;//它的子节点还未用得上 
23     }
24     T[id].minx=min(T[id].minx,x);//更新最小的x值 
25     //下面就是线段树的单点修改 
26     if(L==R)
27         return ;
28     int mid=(L+R)>>1;
29     if(y<=mid)
30         updata(T[id].lson,L,mid,y,x); 
31     else
32         updata(T[id].rson,mid+1,R,y,x);
33 }
34 void query(int id,int L,int R,int l,int r,int x)
35 {
36     if(flag||!id)//如果已经有点满足条件,或者这个节点没开辟就返回 
37         return ;
38     if(l<=L&&r>=R)
39     {
40         if(T[id].minx<=x)
41             flag=1;//在y1和y2范围内有个x满足条件 
42         return ;
43     }
44     int mid=(L+R)>>1;
45     if(l<=mid)
46         query(T[id].lson,L,mid,l,r,x);
47     if(r>mid)
48         query(T[id].rson,mid+1,R,l,r,x);
49 }
50 int main()
51 {
52     int op,x,y,y2,c;
53     init();
54     while(~scanf("%d",&op)&&op!=3)
55     {
56         if(op==0)
57             init();
58         else if(op==1)
59         {
60             scanf("%d%d%d",&x,&y,&c);
61             updata(root[c],1,1000000,y,x);
62         }
63         else
64         {
65             scanf("%d%d%d",&x,&y,&y2);
66             int ans=0;
67             for(int i=0;i<=50;i++)
68             {
69                 flag=0;
70                 query(root[i],1,1000000,y,y2,x);
71                 ans+=flag;
72             }
73             printf("%d
",ans);
74         }
75     }
76     return 0; 
77 }
线段树下线段果

  正解是cdq分治,待我学成归来,再更新。。。我回来了

  cdq分治处理的话,就是三维偏序的一个处理,(操作时间,x轴,y轴),然后第一维已经有序,那么我们cdq分治处理第二维,然后线段树处理第三维。因为最多是50种颜色,那么我们采用状压的策略,把每个颜色C用2C来表示,然后线段树维护个区间或和。需要注意的就是y轴离散化下,不然容易超时。

  1 #include<cstdio>
  2 #include<algorithm>
  3 #include<vector>
  4 #define L(x) (x<<1)
  5 #define R(x) (x<<1|1)
  6 #define M(x) ((T[x].l+T[x].r)>>1)
  7 using namespace std;
  8 typedef long long ll;
  9 const int N=150118,Y=1000118;
 10 struct Tree{
 11     int l,r;
 12     ll val;
 13 }T[Y];
 14 struct Nop{
 15     int op,x,y,y1;
 16     ll val;//op1更新操作的val记录2^C,op2查询操作记录答案编号 
 17     friend bool operator <(const Nop &n1,const Nop &n2){
 18         return n1.x==n2.x ? n1.op<n2.op : n1.x<n2.x;
 19     }
 20 }P[N<<1],temp[N<<1];
 21 int pn=0,qn=0,newy[Y];
 22 bool num[Y]={0};
 23 vector<int> vy;
 24 ll ans[N]={0},cf2[52]={1};
 25 inline void addp(int op,int x,int y,int y1,ll val){
 26     P[pn++]=(Nop){op,x,y,y1,val};
 27 }
 28 inline void addy(int y)
 29 {
 30     if(!num[y])
 31     {
 32         num[y]=1;
 33         vy.push_back(y);
 34     }
 35 }
 36 void built(int id,int l,int r)
 37 {
 38     T[id].val=0;
 39     T[id].l=l,T[id].r=r;
 40     if(l==r)
 41         return ;
 42     built(L(id),l,M(id));
 43     built(R(id),M(id)+1,r);
 44 }
 45 //线段树单点修改 
 46 void updata(int id,int pos,ll val)
 47 {
 48     if(T[id].l==T[id].r&&T[id].l==pos)
 49     {
 50         if(val)
 51             T[id].val|=val;
 52         else
 53             T[id].val=0;
 54         return ;
 55     }
 56     if(pos<=M(id))
 57         updata(L(id),pos,val);
 58     else
 59         updata(R(id),pos,val);
 60     T[id].val=T[L(id)].val|T[R(id)].val;
 61 }
 62 //区间或和查询 
 63 ll query(int id,int l,int r)
 64 {
 65     ll ans=0;
 66     if(l<=T[id].l&&T[id].r<=r)
 67         return T[id].val;
 68     if(l<=M(id))
 69         ans|=query(L(id),l,r);
 70     if(r>M(id))
 71         ans|=query(R(id),l,r);
 72     return ans;
 73 }
 74 void cdq(int l,int r)
 75 {
 76     if(l==r)
 77         return ;
 78     int m=(l+r)>>1;
 79     cdq(l,m);
 80     cdq(m+1,r);
 81     int i=l,j=m+1,k=l;
 82     while(i<=m&&j<=r)
 83     {
 84         if(P[i]<P[j])
 85         {
 86             if(P[i].op==1)
 87                 updata(1,P[i].y,P[i].val);
 88             temp[k++]=P[i++];
 89         }
 90         else
 91         {
 92             if(P[j].op==2)
 93                 ans[P[j].val]|=query(1,P[j].y,P[j].y1);
 94             temp[k++]=P[j++];
 95         }
 96     }
 97     while(i<=m)
 98         temp[k++]=P[i++];
 99     while(j<=r)
100     {
101         if(P[j].op==2)
102             ans[P[j].val]|=query(1,P[j].y,P[j].y1);
103         temp[k++]=P[j++];
104     }
105     for(i=l;i<=r;i++)
106     {
107         if(P[i].op==1)
108             updata(1,P[i].y,0);
109         P[i]=temp[i];
110     }
111 }
112 void solve()
113 {
114     if(pn)
115     {
116         //离散化部分 
117         sort(vy.begin(),vy.end());
118         for(int i=0;i<vy.size();i++)
119         {
120             newy[vy[i]]=i+1;
121             num[vy[i]]=0;
122         }
123         for(int i=0;i<pn;i++)
124         {
125             if(P[i].op==1)
126                 P[i].y=newy[P[i].y];
127             else
128                 P[i].y=newy[P[i].y],P[i].y1=newy[P[i].y1];
129         }
130         //进行分治 
131         cdq(0,pn-1);
132     }
133     for(int i=0;i<qn;i++)
134     {
135         int sum=0;
136         //判断2^0+2^1+2^2+...+2^50含有哪些 
137         for(int j=0;j<=50;j++)
138             if(ans[i]&cf2[j])
139                 sum++;
140         printf("%d
",sum); 
141         ans[i]=0;
142     }
143     pn=qn=0;
144     vy.clear();
145 }
146 int main()
147 {
148     int op,x,y,c,y1;
149     built(1,1,N);
150     for(int i=1;i<=50;i++)
151         cf2[i]=cf2[i-1]<<1;
152     while(~scanf("%d",&op)&&op!=3)
153     {
154         if(op==0)
155             solve();
156         else if(op==1)
157         {
158             scanf("%d%d%d",&x,&y,&c);
159             addp(1,x,y,0,cf2[c]);
160             addy(y);
161         }
162         else
163         {
164             scanf("%d%d%d",&x,&y,&y1);
165             addp(2,x,y,y1,qn++);
166             addy(y);
167             addy(y1);
168         }
169     }
170     solve();
171     return 0;
172 }
一分二二分四

  但实际上,3个实现方法中,暴力最快。。。数据太坑了

原文地址:https://www.cnblogs.com/LMCC1108/p/10699522.html