hdu 5029 Relief grain(ツリーチェーン分割+セグメントツリー)
タイトルリンク:http://acm.hdu.edu.cn/showproblem.php?pid=5029
題意:木と操作を与える.操作a,b,kは,ツリー上のa,bノード間の経路上のノードにk値を加算し,最後に各ノードに最大回加算された数を出力することに相当する.
構想:まず木の鎖で分割して問題を線形構造に変換して、それからどのように線形でこの問題を解決するかを考えます.区間染色に相当し、最後にポイントごとに最も多く染められた色を聞く.
方法:各操作a,b,kに対して、私たちはaノードにkをマークし、b+1ノードに-kをマークし、複数のマークしない私たちはvectorで記憶することができ、まずすべての操作をこの線形の構造に打ち込み、線分ツリーで維持することができる.
区間a~bには、色aから色bまでで最も多く現れる色のラベルが維持されている.これにより、マークされた線形構造を左から右にスキャンし、ノードごとに格納されたラベルを線分ツリーに更新することができる.
は、正の値で対応する色の回数+1、そうでなければ-1、すべてのマークを伝えた後、ルートノードの値(メンテナンスは全区間)をとると、現在最も染められた回数が多い値がわかります.感覚の仕方が巧みだ.
code:
もう1つの方法はsetを使って、まず1つのpairを定義して、そのfirst値は色が現れる回数を保存して、second値は対応する色を保存して、setはまずfisrtを押してソートして、次にsecondのソートを押して、それでいいです.
題意:木と操作を与える.操作a,b,kは,ツリー上のa,bノード間の経路上のノードにk値を加算し,最後に各ノードに最大回加算された数を出力することに相当する.
構想:まず木の鎖で分割して問題を線形構造に変換して、それからどのように線形でこの問題を解決するかを考えます.区間染色に相当し、最後にポイントごとに最も多く染められた色を聞く.
方法:各操作a,b,kに対して、私たちはaノードにkをマークし、b+1ノードに-kをマークし、複数のマークしない私たちはvectorで記憶することができ、まずすべての操作をこの線形の構造に打ち込み、線分ツリーで維持することができる.
区間a~bには、色aから色bまでで最も多く現れる色のラベルが維持されている.これにより、マークされた線形構造を左から右にスキャンし、ノードごとに格納されたラベルを線分ツリーに更新することができる.
は、正の値で対応する色の回数+1、そうでなければ-1、すべてのマークを伝えた後、ルートノードの値(メンテナンスは全区間)をとると、現在最も染められた回数が多い値がわかります.感覚の仕方が巧みだ.
code:
#include
#include
#include
#include
#include
#include
#pragma comment(linker, "/STACK:102400000,102400000")
using namespace std;
const int maxn=105000;
const int maxe=400010;
struct edge
{
int to,next;
} P[maxe];
int head[maxn],si;
int fa[maxn],deep[maxn],son[maxn],num[maxn];
int top[maxn],p[maxn],fp[maxn],pos;
void init()
{
si=0;
memset(head,-1,sizeof(head));
pos=1;
memset(son,-1,sizeof(son));
}
void add_edge(int s,int t)
{
P[si].to=t;
P[si].next=head[s];
head[s]=si++;
}
void dfs1(int u,int pre,int d)
{
deep[u]=d;
fa[u]=pre;
num[u]=1;
for(int i=head[u];i!=-1;i=P[i].next){
int v=P[i].to;
if(v!=pre){
dfs1(v,u,d+1);
num[u]+=num[v];
if(son[u]==-1||num[v]>num[son[u]]) son[u]=v;
}
}
}
void getpos(int u,int sp)
{
top[u]=sp;
p[u]=pos++;
fp[p[u]]=u;
if(son[u]==-1) return ;
getpos(son[u],sp);
for(int i=head[u];i!=-1;i=P[i].next){
int v=P[i].to;
if(v!=son[u]&&v!=fa[u]) getpos(v,v);
}
}
vector w[maxn];
void add(int u,int v,int tt)
{
int f1=top[u],f2=top[v];
while(f1!=f2){
if(deep[f1]deep[v]) swap(u,v);
w[p[u]].push_back(tt);
w[p[v]+1].push_back(-tt);
}
//
int n,cc[maxn];
struct ppp
{
int l,r,dat;
} ss[4*maxn+10];
void Build(int k,int ll,int rr)
{
ss[k].l=ll;
ss[k].r=rr;
if(ll==rr){
ss[k].dat=ll;
return ;
}
else ss[k].dat=0;
Build((k<<1)+1,ll,(ll+rr)/2);
Build((k<<1)+2,(ll+rr)/2+1,rr);
}
void init_tree(int n_)
{
n=1;
while(n0){
k=(k-1)/2;
if(cc[ss[2*k+1].dat]>=cc[ss[2*k+2].dat])
ss[k].dat=ss[2*k+1].dat;
else
ss[k].dat=ss[2*k+2].dat;
}
}
int ans[maxn];
int main()
{
int nn,mm,col;
int s,t,tt;
while(scanf("%d%d",&nn,&mm),nn!=0||mm!=0){
init();
col=0;
memset(ans,0,sizeof(ans));
memset(cc,0,sizeof(cc));
for(int i=1;i0) update(w[i][j],1);
else update(-w[i][j],-1);
}
ans[fp[i]]=ss[0].dat;
}
for(int i=1;i<=nn;i++) printf("%d
",ans[i]);
}
return 0;
}
もう1つの方法はsetを使って、まず1つのpairを定義して、そのfirst値は色が現れる回数を保存して、second値は対応する色を保存して、setはまずfisrtを押してソートして、次にsecondのソートを押して、それでいいです.