[HDU3974] 解题报告
比赛1003
HOJ地址:http://acm.hdu.edu.cn/showproblem.php?pid=3974
N个人,每个人最多一个直接上司,可以有一些下属,人际关系构成一棵有向树。每次给一个人分配任务时,他自己和他所有直接和间接下属都开始做这个任务。
有M条指令。C X表示查询第X个人当前工作。T X Y表示给X这个人分配代号为Y的工作(他自己和他所有直接和间接下属都开始做这个任务)。题目分析:
看起来就是一个线段树的题目。
建树方式如下:找到树的根,DFS遍历一次求出每个点遍历的起始和结束时间,于是每个点对应一个区间。建树染色即可。具体染色方式和POJ2777基本一样。
源代码:
#include <cstdio>
#include <cstdlib>
#include <vector>
#include <algorithm>
using namespace std;
const int maxn=50010;
const int maxl = 50010;
struct node{
int l, r;
int color;
bool cover;
//cover表示是否覆盖了所有孩子的状态
}node[maxl*4];
int start[maxn], end[maxn];
void build(int k, int l, int r)
{
node[k].l = l;;
node[k].r = r;
node[k].cover = true;
node[k].color = 0;
if (l==r) return;
int mid = (l+r)>>1, lson=k<<1, rson=lson+1;
build(lson, l, mid);
build(rson, mid+1, r);
}
void insert(int k, int l, int r, int c)
{
if (node[k].l == l && node[k].r ==r )
{
node[k].color = c;
node[k].cover = true;
return;
}
if (node[k].l < node[k].r)
{
int m = (node[k].l+node[k].r)>>1, lson=k<<1, rson=lson+1;
if (node[k].cover)
{
node[lson].color = node[rson].color = node[k].color;
node[lson].cover = node[rson].cover = true;
node[k].cover = false;
}
if (r<=m)
insert(lson, l, r, c);
else if (l>m)
insert(rson, l, r, c);
else
{
insert(lson, l, m, c);
insert(rson, m+1, r, c);
}
}
}
int query(int k, int l, int r){
if (node[k].l == l && node[k].r ==r)
return node[k].color;
if (node[k].l < node[k].r){
int m = (node[k].l+node[k].r)>>1, lson=k<<1, rson=lson+1;
if (node[k].cover){
node[lson].color = node[rson].color = node[k].color;
node[lson].cover = node[rson].cover = true;
node[k].cover = false;
}
if (r<=m)
return query(lson, l, r);
else if (l>m)
return query(rson, l, r);
else
{
return query(lson, l, m);
}
}
}
void dfs(vector<int> v[], int k, int &sum)
{
start[k]=sum;
for (int i=0; i<v[k].size(); i++)
dfs(v, v[k][i], ++sum);
end[k]=sum;
}
void init(int n)
{
vector<int> v[maxn];
bool f[maxn]={0};
int boss, x, y, sum;
for (int i=0; i<n-1; i++)
{
scanf("%d%d", &x, &y);
x--; y--;
v[y].push_back(x);
f[x]=true;
}
for (int i=0; i<n; i++)
if (f[i]==false){boss=i;break;}
sum=0;
dfs(v, boss, sum);
}
int main(){
char ch[10];
int cs;
int n, m, a, b;
scanf("%d", &cs);
for (int css=1; css<=cs; css++)
{
scanf("%d", &n);
init(n);
build(1, 0, n-1);
printf("Case #%d:\n", css);
scanf("%d", &m);
insert(1, 0, n-1, -1);
while (m--)
{
scanf("%s", ch);
if (ch[0]=='T')
{
scanf("%d%d", &a, &b);
a--;
insert(1, start[a], end[a], b);
}
else{
scanf("%d", &a);
a--;
printf("%d\n", query(1, start[a], end[a]));
}
}
}
return 0;
}
附POJ2777源代码:
(题目大意,染色命令给一段区间染色,查询命令查询区间中一共有多少颜色)
#include <cstdio>
#include <cstdlib>
#include <algorithm>
using namespace std;
const int maxl = 100010;
struct node{
int l, r;
int color;
bool cover;
//cover表示是否覆盖了所有孩子的状态
}node[maxl*4];
void swap(int &a, int &b){
int t;
t = a; a = b; b = t;
}
void build(int k, int l, int r){
node[k].l = l;;
node[k].r = r;
node[k].cover = true;
node[k].color = 1;
if (l==r) return;
int mid = (l+r)>>1;
build(k<<1, l, mid);
build((k<<1)+1, mid+1, r);
}
void insert(int k, int l, int r, int c){
if (node[k].l == l && node[k].r ==r ){
node[k].color = c;
node[k].cover = true;
return;
}
if (node[k].l < node[k].r){
if (node[k].cover){
node[k<<1].color = node[(k<<1)+1].color = node[k].color;
node[k<<1].cover = node[(k<<1)+1].cover = true;
node[k].cover = false;
}
int m = (node[k].l+node[k].r)>>1;
if (r<=m)
insert(k<<1, l, r, c);
else if (l>m)
insert((k<<1)+1, l, r, c);
else {
insert(k<<1, l, m, c);
insert((k<<1)+1, m+1, r, c);
}
node[k].color = node[k<<1].color | node[(k<<1)+1].color;
}
}
int query(int k, int l, int r){
if (node[k].l == l && node[k].r ==r)
return node[k].color;
if (node[k].l < node[k].r){
if (node[k].cover){
node[k<<1].color = node[(k<<1)+1].color = node[k].color;
node[k<<1].cover = node[(k<<1)+1].cover = true;
node[k].cover = false;
}
int m = (node[k].l+node[k].r)>>1;
if (r<=m)
return query(k<<1, l, r);
else if (l>m)
return query((k<<1)+1, l, r);
else {
return (query(k<<1, l, m) | query((k<<1)+1, m+1, r) );
}
}
}
int countbit(int n){
return n ? 1+countbit(n&(n-1)) : 0;
}
int main(){
int L, T, O;
scanf("%d%d%d", &L, &T, &O);
build(1, 1, L);
while(O--){
char ch[3];
int a,b,c;
scanf("%s", ch);
if (ch[0]=='C'){
scanf("%d%d%d", &a, &b, &c);
if (a>b) swap(a,b);
insert(1, a, b, 1<<(c-1));
}
else{
scanf("%d%d", &a, &b);
if (a>b) swap(a,b);
printf("%d\n",countbit(query(1, a, b)));
}
}
return 0;
}
比赛总结:
开场一段时间后才开始做,看到1003的时候比较快想到了线段树,但是建树的思路有问题(现在还是不知道有什么问题),WA了七八次,调了两个多小时。之后温鸿师兄教了一下建树的方法才过了。
一道全场通过最多的大水被我写成这样太不应该了。从开场就不在状态,这五天连续小学期+比赛+机器人也快吃不消了……
总之今天太差了,拖了队伍后腿,对不起。