Assign the task---hdu3974(线段树优化+dfs)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3974
题意就是:公司有n个员工,关系有n-1个,T x y 代表把工作y交给员工x;
员工可以把工作交给下属;
本来是线段树的题,但是我真心看不懂,所以就找了个能看懂的方法了
#include<stdio.h>
#include<iostream>
#include<string.h>
#include<algorithm>
using namespace std;
#define N 50050
int f[N];
struct node
{
int task, order;
}a[N];
int Query(int x)
{
int order = -1, ans = -1;
while(x != 0)
{
if(a[x].order > order)
{
ans = a[x].task;
order = a[x].order;
}
x = f[x];
}
return ans;
}
int main()
{
int T, n, m, t=1, x, y;
char s[10];
scanf("%d", &T);
while(T--)
{
scanf("%d", &n);
memset(a, -1, sizeof(a));
memset(f, 0, sizeof(f));
for(int i=1; i<=n-1; i++)
{
scanf("%d %d", &x, &y);
f[x] = y;
}
scanf("%d", &m);
printf("Case #%d:\n", t++);
for(int i=1; i<=m; i++)
{
scanf("%s", s);
if(s[0] == 'C')
{
scanf("%d", &x);
printf("%d\n", Query(x));
}
else
{
scanf("%d %d", &x, &y);
a[x].order = i;//工作的顺序;
a[x].task = y;
}
}
}
return 0;
}
看了学长的代码,有点理解了,就写了一下;
补充一下线段树的方法吧
可以用每个节点的所包含的子节点段来当做线段树的节点,查找每个节点所包含的段可以用简单的DFS实现。
#include<stdio.h>
#include<vector>
#include<iostream>
#include<string.h>
#include<algorithm>
#define N 50050
#define Lson r<<1
#define Rson r<<1|1
#define INF 0xfffffff
using namespace std;
int s[N], e[N], used[N], index;//s表示每个员工所有下属的开始和结束节点,包含本身
vector<int>G[N];
struct SegTree
{
int L, R, task, vis;
int mid()
{
return (L+R)>>1;
}
int len()
{
return R-L+1;
}
}a[N<<2];
void dfs(int k)
{
s[k]=++index;
for(int i=0,len=G[k].size(); i<len; i++)
dfs(G[k][i]);
e[k]=index;
}
void BuildTree(int r, int L, int R)
{
a[r].L = L; a[r].R = R;
a[r].task = -1; a[r].vis = 0;
if(L == R)return ;
BuildTree(Lson, L, a[r].mid());
BuildTree(Rson, a[r].mid()+1,R);
}
void Down(int r)
{
if(a[r].L != a[r].R && a[r].vis == 1)
{
a[Lson].vis = a[Rson].vis = 1;
a[Lson].task = a[Rson].task = a[r].task;
a[r].vis = 0;
}
}
void Update(int r, int L, int R, int k)
{
Down(r);
if(a[r].L == L && a[r].R == R)
{
a[r].task = k;
a[r].vis = 1;
return;
}
if(R <= a[r].mid())
Update(Lson, L, R, k);
else if(L > a[r].mid())
Update(Rson, L, R, k);
else
{
Update(Lson, L, a[r].mid(), k);
Update(Rson, a[r].mid()+1, R, k);
}
}
int Query(int r, int k)
{
Down(r);
if(a[r].L == a[r].R)
return a[r].task;
if(k<=a[r].mid())
return Query(Lson, k);
else
return Query(Rson, k);
}
int main()
{
int T, t=1, n, m, x, y, u, v;
scanf("%d", &T);
while(T--)
{
scanf("%d", &n);
memset(used, 0, sizeof(used));
for(int i=0;i<=n;i++)
G[i].clear();
for(int i=1; i<n; i++)
{
scanf("%d %d", &u, &v);
G[v].push_back(u);
used[u] = 1;
}
index = 0;
for(int i=1; i<=n; i++)
{
if(used[i]==0)
{
dfs(i);break;
}
}
BuildTree(1, 1, n);
printf("Case #%d:\n", t++);
scanf("%d", &m);
while(m--)
{
char str[5];
scanf("%s", str);
if(str[0]=='C')
{
scanf("%d", &x);
printf("%d\n", Query(1,s[x]));
}
else
{
scanf("%d%d", &x, &y);
Update(1, s[x], e[x], y);
}
}
}
return 0;
}
很久之后的今天20160505再来看这道题,完全不是很难看懂的状态了
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <stack>
#include <vector>
using namespace std;
typedef long long LL;
#define met(a, b) memset(a, b, sizeof(a))
#define N 50011
#define Lson r<<1
#define Rson r<<1|1
struct node
{
int L, R, task, flag;///flag表示此区间是否被全部覆盖,如果是那么task表示此区间的工作是什么;
int Mid(){ return (L+R)/2; }
int Len(){ return (R-L+1); }
}a[N*4];
vector<vector<int> >G;
int s[N], e[N], du[N], Index;
void dfs(int u)
{
s[u] = ++Index;///相当于是记录u得起始下属下标,结束下标在递归回来的时候确定的,
int len = G[u].size();
for(int i=0; i<len; i++)
dfs(G[u][i]);
e[u] = Index;
}
void Build(int r, int L, int R)
{
a[r].L = L, a[r].R = R; a[r].task = -1;
if( L == R )return;
Build(Lson, L, a[r].Mid());
Build(Rson, a[r].Mid()+1, R);
}
void Down(int r)
{
if(a[r].flag && a[r].L != a[r].R)
{
a[Lson].flag = a[Rson].flag = a[r].flag;
a[Lson].task = a[Rson].task = a[r].task;
a[r].flag = 0;
}
}
void Update(int r, int L, int R, int task)
{
if(a[r].L == L && a[r].R == R)
{
a[r].flag = 1;
a[r].task = task;
return ;
}
Down(r);
if( R <= a[r].Mid() )
Update(Lson, L, R, task);
else if( L > a[r].Mid() )
Update(Rson, L, R, task);
else
{
Update(Lson, L, a[r].Mid(), task);
Update(Rson, a[r].Mid()+1, R, task);
}
}
int Query(int r, int pos)
{
Down(r);///因为上面也许没有更新到最底部,所以要再接着往下压;
if(a[r].L == a[r].R)///找到叶子节点,并返回;
return a[r].task;
if(pos <= a[r].Mid())
return Query(Lson, pos);
else
return Query(Rson, pos);
}
int main()
{
int T, n, m, u, v, x, y, t = 1;
scanf("%d", &T);
while(T--)
{
met(du, 0); met(s, 0); met(e, 0);
scanf("%d", &n);
G.clear();
G.resize(n+5);
for(int i=1; i<n; i++)
{
scanf("%d %d", &u, &v);
G[v].push_back(u);
du[u] = 1;
}
Index = 0;
for(int i=1; i<=n; i++)
{
if(!du[i])///找到根节点,然后按照递归的形式找到自己连续的下属;
{
dfs(i);break;
}
}
Build(1, 1, n);
scanf("%d", &m);
printf("Case #%d:\n", t++);
while(m--)
{
char ch[15];
scanf("%s", ch);
if(ch[0]=='T')
{
scanf("%d %d", &x, &y);
Update(1, s[x], e[x], y);///更新的是x这个人的所有下属;
}
else
{
scanf("%d", &x);
printf("%d\n", Query(1, s[x]));
}
}
}
return 0;
}