[HDU3974] 解题报告 && 多校联合反思

[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了七八次,调了两个多小时。之后温鸿师兄教了一下建树的方法才过了。
一道全场通过最多的大水被我写成这样太不应该了。从开场就不在状态,这五天连续小学期+比赛+机器人也快吃不消了……
总之今天太差了,拖了队伍后腿,对不起。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值