Jzoj5462【NOIP2017提高A组冲刺11.8】证书
Pulumi生活在P城的角落,而他的朋友们gjdy,oyski,tutuwai等等生活在P城的靠中心位置。
P城很大,但它拥有优秀的城市结构,同时P城重视文化教育的发展,P城共有n个学校,校与校之间共建立了n-1条交通线路,且两所学校之间存在唯一的连通路径。
P城常常举行各种类型的评比活动,为了节约资金,最终将给某一条路径上的所有学校颁发证书。为了便于描述我们记一次评比活动的结果为(ui,vi,zi)表示路径(ui,vi)上的所有学校获得一个类型为zi的证书。
一个学校若为Zmax类型的学校,则表示它在Zmax类型下的证书数量最多(如果有相同数量的类型,取类型标号最小一个)。
P城很大,但它拥有优秀的城市结构,同时P城重视文化教育的发展,P城共有n个学校,校与校之间共建立了n-1条交通线路,且两所学校之间存在唯一的连通路径。
P城常常举行各种类型的评比活动,为了节约资金,最终将给某一条路径上的所有学校颁发证书。为了便于描述我们记一次评比活动的结果为(ui,vi,zi)表示路径(ui,vi)上的所有学校获得一个类型为zi的证书。
一个学校若为Zmax类型的学校,则表示它在Zmax类型下的证书数量最多(如果有相同数量的类型,取类型标号最小一个)。
Pulumi收集了本年度所有的评比活动结果,共m次。他很感兴趣所有学校的类型,以了解他朋友们学校的状况,现在他忙于出题,把这个任务交给了你。
本来以为区间众数只能莫队做了呢结果发现可以用线段树合并
考场上以为区间众数不满足区间价法(对于普通线段树确实不满足,但是这里应该用权值线段树)
写了启发式map合并结果错一堆
首先输出答案没有换行(这已经没分了)
第二dfs时候爆栈了
而且一个地方没有判零
好吧说一下正解:
我们对于一条路径,在端点处打上两个+1,在lca打上一个-1,在f[lca]打上一个-1
那么答案就是整个子树的众数
我们开一个map一个set,一个代表的是size,即size[x][k]表示k在x的子树中出现了几次
set存一个pair,这个pair的first代表的是size[x][k]的值,second是k,整体按照first作为优先级
set其实就是用来统计答案的,合并的是map
卡栈?参考几天前那个什么游戏那篇的
居然速度还不错看来O(nlg^2n)还是挺可靠的(还不是因为自己开了O3)
#pragma GCC optimize("O3")
#pragma G++ optimize("O3")
#include<map>
#include<set>
#include<vector>
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<algorithm>
#define N 120010
using namespace std;
struct pr{ int x,y; };
extern int main2(void) __asm__ ("main2");
inline bool operator< (pr a,pr b){ return a.x==b.x?a.y<b.y:a.x>b.x; }
vector<int> G[N]; set<pr> r[N];
vector<pr> w[N]; map<int,int> s[N];
int sz[N],top[N],f[N],son[N],rt[N];
int n,m,d[N],A[N];
void dfs(int x,int p){
f[x]=p; sz[x]=1; d[x]=d[p]+1;
for(int v,i=0;i<G[x].size();++i)
if((v=G[x][i])!=p){
dfs(v,x);
sz[x]+=sz[v];
if(sz[v]>sz[son[x]]) son[x]=v;
}
}
void dijk(int x,int p){
top[x]=p;
if(son[x]) dijk(son[x],p);
for(int v,i=0;i<G[x].size();++i)
if((v=G[x][i])!=f[x] && v!=son[x]) dijk(v,v);
}
inline int gLca(int x,int y,int c){
w[x].push_back((pr){c,1});
w[y].push_back((pr){c,1});
for(;top[x]!=top[y];y=f[top[y]])
if(d[top[x]]>d[top[y]]) swap(x,y);
if(d[x]>d[y]) x=y;
w[x].push_back((pr){c,-1});
w[f[x]].push_back((pr){c,-1});
return x;
}
inline void merge(int x,int v){
for(map<int,int>::iterator it=s[v].begin();it!=s[v].end();++it){
int val=it->first,siz=s[x][val],ds=it->second;
if(siz==0) r[x].insert((pr){ds,val});
else { r[x].erase((pr){siz,val}); if(siz+ds) r[x].insert((pr){siz+ds,val}); }
s[x][val]+=ds;
}
s[v].clear(); r[v].clear();
}
void cal(int x){
if(son[x]){
cal(son[x]);
rt[x]=rt[son[x]];
} else rt[x]=x;
for(int v,i=0;i<G[x].size();++i)
if((v=G[x][i])!=f[x] && v!=son[x]) {
cal(v);
merge(rt[x],rt[v]);
}
int r1=rt[x];
for(vector<pr>::iterator it=w[x].begin();it!=w[x].end();++it){
int val=it->x,siz=s[r1][val];
if(siz==0) r[r1].insert((pr){it->y,val});
else { r[r1].erase((pr){siz,val}); r[r1].insert((pr){siz+it->y,val}); }
s[r1][val]+=it->y;
}
if(r[r1].empty()||r[r1].begin()->x<=0) A[x]=0;
else A[x]=r[r1].begin()->y;
}
int main2(){
freopen("certif.in","r",stdin);
freopen("certif.out","w",stdout);
scanf("%d%d",&n,&m);
for(int x,y,i=1;i<n;++i){
scanf("%d%d",&x,&y);
G[x].push_back(y);
G[y].push_back(x);
}
dfs(1,0); dijk(1,1);
for(int x,y,c;m--;){
scanf("%d%d%d",&x,&y,&c);
gLca(x,y,c);
}
cal(1);
for(int i=1;i<=n;++i) printf("%d\n",A[i]);
exit(0);
}
int main(){
int size = 256 << 20; // 256Mb
char *p = (char *)malloc(size) + size;
__asm__ __volatile__(
"movq %0, %%rsp\n"
"pushq $exit\n"
"jmp main2\n"
:: "r"(p));
}