[NOIP2018模擬賽10.19]只會暴力報告
阿新 • • 發佈:2018-11-09
閒扯
今天又是暴力滿滿(並不)的一天呢
昨天老師說了分數要正態分佈,今天看起來...不過暴力分很多,雖然我人太傻逼又沒打滿
T1 woc?不是說送分的嗎,看起來又是個樹形DP神題,暴力告辭,鏈上的搞一搞
T2 woc?又是樹 紀中這麼喜歡出圖/樹題的嗎?第一眼暴力dij告辭
T3 woc?又又又是樹?!看起來十分碼農?!部分分還好很多,想到昨天老師提到了天天愛跑步的例子,感覺可以搞一搞...於是就開始爆肝了...結果期望30分開了個fread爆0了
\(30+30+0\)涼涼,T2堆改成\(paring\)_\(heap\)就50了,辣雞STL.雖然有一個更優的暴力...
T1 lkf
又是道神奇樹形DP,分析先咕會
/* code by RyeCatcher */ inline char gc(){ static char buf[SIZE],*p1=buf,*p2=buf; return p1==p2&&(p2=(p1=buf)+fread(buf,1,SIZE,stdin),p1==p2)?EOF:*p1++; } #define gc getchar template <class T>inline void read(T &x){ x=0;int ne=0;char c; while((c=gc())>'9'||c<'0')ne=c=='-';x=c-48; while((c=gc())>='0'&&c<='9')x=(x<<3)+(x<<1)+c-48;x=ne?-x:x;return ; } const int maxn=3335; const int inf=0x7fffffff; const int P=19260817; struct Edge{ int ne,to; }edge[maxn<<1]; int h[maxn],num_edge=1; inline void add_edge(int f,int to){ edge[++num_edge].ne=h[f]; edge[num_edge].to=to; h[f]=num_edge; } int n,k,w[maxn],mx=-inf; int id,o,lim; ll f[maxn][maxn]; ll ans=0; void dfs(int now,int fa){ int v;ll p=1; //printf("%d %d\n",now,fa); for(ri i=h[now];i;i=edge[i].ne){ v=edge[i].to; if(v==fa)continue; if(w[v]>=o&&w[v]<=o+lim&&(w[v]!=o||(w[v]==o&&v>id))){ dfs(v,now); //printf("%d %d %d\n",fa,now,v); p=p*(f[v][lim]+1)%P; } } f[now][lim]=p; return ; } int main(){ int x,y; read(n),read(k); for(ri i=1;i<=n;i++){ read(w[i]); } for(ri i=1;i<n;i++){ read(x),read(y); add_edge(x,y); add_edge(y,x); } for(ri i=1;i<=n;i++){ o=w[i],id=i,lim=k; dfs(i,0); //puts("wtf"); if(k==0){ ans=(ans+f[i][k])%P; } else{ lim=k-1; dfs(i,0); ans=(ans+(f[i][k]-f[i][lim])%P+P)%P; } } printf("%lld\n",ans%P); return 0; }
T2 worry
有個性質就是因為你樹上邊隨便走,你斷掉一條樹邊後你最多走一條非樹邊。\(naiive\)的做法就是枚舉了,有沒有更高明的呢?
我們邊從小到大排序,發現對於邊\((x,y)\),它影響\((x,y)\)路徑上的邊(也就是斷掉路徑上的任何一條邊還可以通過\((x,y)\)聯通),也就是\(x,y\)分別到\(lca(x,y)\)路徑上的
樹鏈剖分
那麼鏈剖就可以搞嘍,線段樹維護一個永久標記,如果有標記了也不管(因為邊權從小到大排序)
跑得還挺快
/* code by RyeCatcher */ inline char gc(){ static char buf[SIZE],*p1=buf,*p2=buf; return p1==p2&&(p2=(p1=buf)+fread(buf,1,SIZE,stdin),p1==p2)?EOF:*p1++; } template <class T>inline void read(T &x){ x=0;int ne=0;char c; while((c=gc())>'9'||c<'0')ne=c=='-';x=c-48; while((c=gc())>='0'&&c<='9')x=(x<<3)+(x<<1)+c-48;x=ne?-x:x;return ; } const int maxn=200005; const int inf=0x7fffffff; int n,m; struct Edge{ int ne,to; ll dis; }edge[maxn<<1]; int h[maxn],num_edge=1; inline void add_edge(int f,int to,ll c){ edge[++num_edge].ne=h[f]; edge[num_edge].to=to; edge[num_edge].dis=c; h[f]=num_edge; } pair<int,int> qwq[maxn]; struct Niconiconi{ int x,y; ll dis; Niconiconi(){x=y=dis=0;} Niconiconi(int _x,int _y,ll _c){x=_x,y=_y,dis=_c;} bool operator <(const Niconiconi &rhs)const{ return dis<rhs.dis; } }con[maxn<<1]; int dep[maxn],fa[maxn],son[maxn],size[maxn],top[maxn],dfn[maxn],rnk[maxn],tot=0; void dfs1(int now){ int v; size[now]=1; //printf("%d %d\n",now,fa[now]); for(ri i=h[now];i;i=edge[i].ne){ v=edge[i].to; if(v==fa[now])continue; dep[v]=dep[now]+1,fa[v]=now; dfs1(v); size[now]+=size[v]; if(!son[now]||size[son[now]]<size[v])son[now]=v; } return ; } void dfs2(int now,int t){ int v; top[now]=t,dfn[now]=++tot,rnk[tot]=now; if(!son[now])return ; dfs2(son[now],t); for(ri i=h[now];i;i=edge[i].ne){ v=edge[i].to; if(v==fa[now]||v==son[now])continue; dfs2(v,v); } return ; } int tag[maxn<<2],w[maxn]; int L,R,dta; inline void pushdown(int now){ if(!tag[now<<1])tag[now<<1]=tag[now];//tag[now<<1|1]=tag[now]; if(!tag[now<<1|1])tag[now<<1|1]=tag[now]; } void update(int now,int l,int r){ if(tag[now])return ; if(L<=l&&r<=R){ tag[now]=dta; return ; } int mid=(l+r)>>1; pushdown(now); if(L<=mid&&!tag[now<<1])update(now<<1,l,mid); if(mid<R&&!tag[now<<1|1])update(now<<1|1,mid+1,r); return ; } void ahaha(int now,int l,int r){ if(l==r){ if(tag[now])w[rnk[l]]=tag[now]; else w[rnk[l]]=-1; return ; } int mid=(l+r)>>1; pushdown(now); ahaha(now<<1,l,mid); ahaha(now<<1|1,mid+1,r); return ; } inline void update_path(int x,int y){ while(top[x]!=top[y]){ if(dep[top[x]]<dep[top[y]])std::swap(x,y); L=dfn[top[x]],R=dfn[x]; update(1,1,n); x=fa[top[x]]; } if(dep[x]>dep[y])std::swap(x,y); L=dfn[x]+1,R=dfn[y]; //printf("--%d %d--\n",rnk[L],rnk[R]); if(L>R)return ; update(1,1,n); } int main(){ int x,y;ll z; FO(worry); read(n),read(m); for(ri i=1;i<n;i++){ read(x),read(y); add_edge(x,y,0); add_edge(y,x,0); qwq[i]=pair<int,int>(x,y); } for(ri i=1;i<=m;i++){ read(x),read(y),read(z); con[i]=Niconiconi(x,y,z); } std::sort(con+1,con+1+m); dep[1]=0,fa[1]=0; dfs1(1); dfs2(1,1); memset(tag,0,sizeof(tag)); for(ri i=1;i<=m;i++){ x=con[i].x,y=con[i].y,dta=con[i].dis; update_path(x,y); } ahaha(1,1,n); for(ri i=1;i<n;i++){ x=qwq[i].first,y=qwq[i].second; if(dep[x]<dep[y])std::swap(x,y); printf("%d\n",w[x]); } return 0; }
並查集
題解是更高明的並查集做法,我還是Too Young Too Simple,只會SB暴力樹剖
每個點指向下一個沒被打標記的點\(nxt[x]\)(以點代邊),顯然這是可傳遞的
這樣的話每次查詢直接往上跳就好了,連LCA都不用求
居然跑到rank1哈哈
/*
code by RyeCatcher
*/
inline char gc(){
static char buf[SIZE],*p1=buf,*p2=buf;
return p1==p2&&(p2=(p1=buf)+fread(buf,1,SIZE,stdin),p1==p2)?EOF:*p1++;
}
#define gc getchar
template <class T>inline void read(T &x){
x=0;int ne=0;char c;
while((c=gc())>'9'||c<'0')ne=c=='-';x=c-48;
while((c=gc())>='0'&&c<='9')x=(x<<3)+(x<<1)+c-48;x=ne?-x:x;return ;
}
const int maxn=100005;
const int inf=0x7fffffff;
int n,m;
struct Edge{
int ne,to;
}edge[maxn<<1];
int h[maxn],num_edge=1;
inline void add_edge(int f,int to){
edge[++num_edge].ne=h[f];
edge[num_edge].to=to;
h[f]=num_edge;
}
struct Niconiconi{
int x,y,z;
bool operator <(const Niconiconi &qwq)const{
return z<qwq.z;
}
}nico[maxn];
int ans[maxn],dep[maxn],fa[maxn],nxt[maxn],fa_id[maxn];
int get(int x){return (nxt[x]==x)?nxt[x]:nxt[x]=get(nxt[x]);}
void dfs(int now){
int v;
for(ri i=h[now];i;i=edge[i].ne){
if((v=edge[i].to)==fa[now])continue;
fa[v]=now,dep[v]=dep[now]+1,fa_id[v]=i;
dfs(v);
}
return ;
}
int main(){
int x,y,z,p;
FO(worry);
read(n),read(m);nxt[n]=n;
for(ri i=1;i<n;i++){
read(x),read(y);
add_edge(x,y),add_edge(y,x);
nxt[i]=i;
}
for(ri i=1;i<=m;i++){
read(nico[i].x),read(nico[i].y),read(nico[i].z);
}
std::sort(nico+1,nico+1+m);
fa[1]=0,dfs(1);
for(ri i=1;i<=m;i++){
x=get(nico[i].x),y=get(nico[i].y),z=nico[i].z;
while(x!=y){
if(dep[x]<dep[y])std::swap(x,y);
ans[fa_id[x]]=z;
nxt[x]=x=get(fa[x]);
}
}
p=2*n;
for(ri i=2;i<p;i+=2){
printf("%d\n",ans[i]?ans[i]:(ans[i^1]?ans[i^1]:-1));
}
return 0;
}