2018年6月4号(线段树)

Posted zssmg

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了2018年6月4号(线段树)相关的知识,希望对你有一定的参考价值。

  今天想和大家一起了解下今天我刚写的一道题:

  P1558 色板游戏

  题目背景

  阿宝上学了,今天老师拿来了一块很长的涂色板。

  题目描述

  色板长度为L,L是一个正整数,所以我们可以均匀地将它划分成L块1厘米长的小方格。并从左到右标记为1, 2, ... L。现在色板上只有一个颜色,老师告诉阿宝在色板上只能做两件事:1. "C A B C" 指在A到 B 号方格中涂上颜色 C。2. "P A B" 指老师的提问:A到 B号方格中有几种颜色。学校的颜料盒中一共有 T 种颜料。为简便起见,我们把他们标记为 1, 2, ... T. 开始时色板上原有的颜色就为1号色。 面对如此复杂的问题,阿宝向你求助,你能帮助他吗?

  输入输出格式

  输入格式:

 

  第一行有3个整数 L (1 <= L <= 100000), T (1 <= T <= 30) 和 O (1 <= O <= 100000). 在这里O表示事件数, 接下来 O 行, 每行以 "C A B C" 或 "P A B" 得形式表示所要做的事情(这里 A, B, C 为整数, 可能A> B)

  输出格式:
 

对于老师的提问,做出相应的回答。每行一个整数。

 

  输入输出样例

  输入样例#1: 复制
  2 2 4
  C 1 1 2
  P 1 2
  C 2 2 2
  P 1 2
  输出样例#1: 复制
  2
  1
  这道题最主要的是处理颜色,首先我们可以想到暴力枚举颜色,经过多年的经验(其实就那么几天);
绝对会超时;
所以我去询问了我们班大佬,打听到一个好方法:用二进制代替有无用这种颜色;
eg:10101表示用了1和3和5编号颜色,没有用其他;
有人会问如何将左子树和右子树合并,所以我们就必须用或(|);
有如下效果:
  100
|  001
---------
101
就进行合并了;
所以代码就很好实现:
 1 #include<bits/stdc++.h>
 2 #define zhi 100001
 3 using namespace std;
 4 struct node{
 5     int l,r,dis,vis;
 6 }tree[zhi*4];
 7 int x,y,t;
 8 void buid(int p,int l,int r)
 9 {
10     tree[p].l=l;
11     tree[p].r=r;
12     tree[p].dis=1;
13     if(l==r)
14     return ;
15     buid(p*2,l,(l+r)/2);
16     buid(p*2+1,(l+r)/2+1,r);
17 }
18 int zhuang(int s)
19 {
20     int tot=0;
21     while(s!=0)
22     {
23         if(s%2)
24         tot++;
25         s/=2;
26     }
27     return tot;
28 }
29 void pdown(int p)
30 {
31     if(tree[p].vis)
32     {
33         tree[p*2].dis=tree[p].vis;
34         tree[p*2].vis=tree[p].vis;
35         tree[p*2+1].dis=tree[p].vis;
36         tree[p*2+1].vis=tree[p].vis;
37         tree[p].vis=0;
38     }
39 }
40 void xiugai(int p)
41 {
42     if(x<=tree[p].l&&y>=tree[p].r)
43     {
44         tree[p].dis=(1<<t);
45         tree[p].vis=tree[p].dis;
46         return ;
47     }
48     pdown(p);
49     int mid=(tree[p].l+tree[p].r)/2;
50     if(x<=mid)
51     xiugai(p*2);
52     if(y>mid)
53     xiugai(p*2+1);
54     tree[p].dis=tree[p*2].dis|tree[p*2+1].dis;
55 }
56 int ask(int p)
57 {
58     if(x<=tree[p].l&&y>=tree[p].r)
59     return tree[p].dis;
60     pdown(p);
61     int mid=(tree[p].l+tree[p].r)/2,a=0,b=0;
62     if(x<=mid)
63     a=ask(p*2);
64     if(y>mid)
65     b=ask(p*2+1);
66     return a|b;
67 }
68 int main()
69 {
70     char u;
71     int m,n,l,a,b;
72     cin>>n>>m>>l;
73     buid(1,1,n);
74     for(int i=1;i<=l;++i)
75     {
76         cin>>u;
77         cin>>a>>b;
78         x=min(a,b);
79         y=max(a,b);
80         if(u==C)
81         {
82             cin>>t;
83             t--;
84             xiugai(1);
85         }
86         else
87         printf("%d\n",zhuang(ask(1)));
88     }
89     return 0;
90 }

today is over!

以上是关于2018年6月4号(线段树)的主要内容,如果未能解决你的问题,请参考以下文章

2018年6月2号(线段树)

2018年6月3号(线段树)

洛谷P2826 [USACO08NOV]光开关Light Switching [2017年6月计划 线段树02]

洛谷P2073 送花 [2017年6月计划 线段树01]

ACM训练小结-柳志轩-2018年6月16日

2018年6月5号(离散化)