WXHCoder Round 9!(取名風格真是女少口阿 )
T1:獻給逝去公主的七重奏
題目大意:
原題:Codechef WEASELTX
樹上每個點有權值,每次操作爲將所有點的權值變爲子樹中所有點權值的異或和。
Q次詢問(相互獨立),問次操作後根節點的權值。
題目分析:
考慮一個點在次操作後對它的級祖先的貢獻次數
有前綴和
這很像組合數路徑數的形式,轉化一下發現:
同時有,所以
那麼對於同一深度的點我們就知道了它的貢獻次數。
而 當且僅當 (爲1的二進制位都必須爲1)
進一步的,當且僅當
對於,設的最高二進制位爲,當時,等價於
所以只需要對預處理答案就可以了。
暴力子集卷積是的,可以用的卷積,就是了。
Code:
#include<bits/stdc++.h>
#define maxn 270005
using namespace std;
int n,Q,dep[maxn],mxd,s[maxn],ans[maxn];
int fir[maxn],nxt[maxn<<1],to[maxn<<1],tot;
inline void line(int x,int y){nxt[++tot]=fir[x],fir[x]=tot,to[tot]=y;}
void dfs(int u,int ff){
mxd=max(mxd,dep[u]);
for(int i=fir[u],v;i;i=nxt[i]) if((v=to[i])!=ff) dep[v]=dep[u]+1,dfs(v,u);
}
void FMT(int *a,int len){
for(int i=2,l=1;i<=len;l=i,i<<=1)
for(int j=0;j<len;j+=i) for(int k=j;k<j+l;k++)
a[k+l]^=a[k];
}
int main()
{
int x,y;
scanf("%d%d",&n,&Q);
for(int i=1;i<n;i++) scanf("%d%d",&x,&y),line(x,y),line(y,x);
dfs(1,0);
for(int i=1;i<=n;i++) scanf("%d",&x),s[dep[i]]^=x;
int len=1; while(len<=mxd) len<<=1; int all=len-1;
ans[0]=s[0],FMT(s,len);
for(int S=1;S<1<<len;S++) ans[S]=s[all-(S-1)];
while(Q--) scanf("%d",&x),printf("%d\n",ans[x&all]);
}
T2:幽雅的綻放吧,墨染的櫻花
題目大意:
經過prufer序列的轉化後大意爲:給出序列,第個多項式是求個多項式乘起來後的的係數。
題目分析:
暴力,優化。
另外一種做法:
把多項式看做無窮項,最終的多項式可以表示爲:
後面的可以直接展開,中間的式子分治NTT即可。
Code:
#include<bits/stdc++.h>
#define maxn 135005
using namespace std;
const int mod = 998244353;
typedef vector<int> Poly;
int w[maxn],WL,r[maxn],lg[maxn];
int Pow(int a,int b){
int s=1; for(;b;b>>=1,a=1ll*a*a%mod) if(b&1) s=1ll*s*a%mod;
return s;
}
void init(int n){
for(WL=1;WL<=n;WL<<=1); w[0]=1,w[1]=Pow(3,(mod-1)/WL);
for(int i=2;i<=WL;i++) w[i]=1ll*w[i-1]*w[1]%mod,lg[i]=lg[i>>1]+1;
}
inline void upd(int &x){x+=x>>31&mod;}
void NTT(int *a,int len,int flg){
for(int i=0;i<len;i++) if(i<r[i]) swap(a[i],a[r[i]]);
for(int i=2,l=1;i<=len;l=i,i<<=1){
for(int j=0,v,t=WL/i;j<len;j+=i) for(int k=j,o=0;k<j+l;k++,o+=t)
v=1ll*w[flg^1?WL-o:o]*a[k+l]%mod,upd(a[k+l]=a[k]-v),upd(a[k]+=v-mod);
}
if(flg^1) for(int i=0,Inv=Pow(len,mod-2);i<len;i++) a[i]=1ll*a[i]*Inv%mod;
}
int n,m,a[maxn],sum,Pw=1,fac[maxn],inv[maxn];
Poly Mul(const Poly &a,const Poly &b){
static int A[maxn],B[maxn]; int n=a.size(),m=b.size(),len=1<<(lg[n+m-1]+1);
for(int i=0;i<len;i++) A[i]=i<n?a[i]:0, B[i]=i<m?b[i]:0, r[i]=r[i>>1]>>1|(i&1?len>>1:0);
NTT(A,len,1),NTT(B,len,1);
for(int i=0;i<len;i++) A[i]=1ll*A[i]*B[i]%mod;
NTT(A,len,-1);
return Poly(A,A+n+m-1);
}
Poly solve(int i,int l,int r){
if(l==r) {Poly f(2); f[0]=1,f[1]=a[l]; return f;}
int mid=(l+r)>>1;
Poly L=solve(i<<1,l,mid),R=solve(i<<1|1,mid+1,r);
return Mul(L,R);
}
int main()
{
scanf("%d",&n); if(n==1) return puts("0"),0;
for(int i=1;i<=n;i++) scanf("%d",&a[i]),sum=(sum+a[i])%mod,Pw=1ll*Pw*a[i]%mod;
fac[0]=fac[1]=inv[0]=inv[1]=1;
for(int i=2;i<=n;i++) fac[i]=1ll*fac[i-1]*i%mod,inv[i]=1ll*(mod-mod/i)*inv[mod%i]%mod;
for(int i=2;i<=n;i++) inv[i]=1ll*inv[i]*inv[i-1]%mod;
init(n); Poly F=solve(1,1,n);
int ans=0;
for(int i=0,pw=1;i<n-1;i++,pw=1ll*pw*sum%mod) ans=(ans+1ll*pw*inv[i]%mod*F[n-2-i])%mod;
printf("%d\n",1ll*ans*Pw%mod*fac[n-2]%mod);
}
T3:竹取飛翔
題目描述:
原題:UOJ#268. 【清華集訓2016】數據交互
路徑交是指點相交。
題目分析:
兩條相交的鏈,其中一條鏈的必然在另一條鏈上。
在每個點上存兩個值,表示鏈LCA爲的鏈的權值和,表示鏈經過點但LCA不爲的權值和。
接下來的操作這篇博客裏面講的超好。
做一點補充說明(定義都在上面那篇博客中):
動態DP的常見操作重鏈剖分,然後維護輕兒子,然後線段樹維護重鏈的答案。
全局的答案再用一個(可刪)堆維護,每次修改先刪掉原來的,再加入新的。
區間修改與無關,比較好寫。單點修改時需要往上跳重鏈修改,的維護同樣需要一個堆,而輕兒子對它的貢獻就是它線段樹的 (),同樣要先刪再修改再添加。重鏈上單點的需要用進行更新,就是這個點的
因爲線段樹的查詢都是對整條重鏈的查詢,所以對每條重鏈分別開線段樹就不需要query了,實現也很簡單,就動態開點記一下左右兒子和根,範圍就是dfs序的範圍。
Code:
#include<bits/stdc++.h>
#define maxn 100005
#define LL long long
using namespace std;
int n,m,dep[maxn],fa[maxn],siz[maxn],son[maxn],top[maxn],dfn[maxn],bot[maxn],ln[maxn],tim;
int fir[maxn],nxt[maxn<<1],to[maxn<<1],tot;
inline void line(int x,int y){nxt[++tot]=fir[x],fir[x]=tot,to[tot]=y;}
struct Heap{
priority_queue<LL>A,B;
void erase(LL x){B.push(x);}
void push(LL x){A.push(x);}
LL top(){while(!B.empty()&&A.top()==B.top()) A.pop(),B.pop(); return A.empty()?0:A.top();}
LL sec(){
LL x=top(); if(A.empty()) return 0; A.pop();
LL y=top(); return A.push(x),y;
}
}ans,g[maxn];
struct data{
LL lx,rx,mx,sa,tag;//lx: gv+[l,v] rx: gu+bu+[u,r] mx: maxsubsequence sa:sum of a tag: add of b
void add(LL v){rx+=v,mx+=v,tag+=v;}
data operator + (const data &B){
return (data){max(lx,sa+B.lx), max(B.rx,rx+B.sa), max(mx,max(B.mx,rx+B.lx)), sa+B.sa, 0};
}
}t[maxn<<2];
int rt[maxn],lc[maxn<<2],rc[maxn<<2],sz;
void build(int &i,int l,int r){if(i=++sz,l!=r) build(lc[i],l,l+r>>1),build(rc[i],(l+r>>1)+1,r);}
void dfs1(int u,int ff){
siz[u]=1,dep[u]=dep[fa[u]=ff]+1;
for(int i=fir[u],v;i;i=nxt[i]) if((v=to[i])!=ff){
dfs1(v,u),siz[u]+=siz[v];
if(siz[v]>siz[son[u]]) son[u]=v;
}
}
void dfs2(int u,int tp){
top[u]=tp,ln[dfn[u]=++tim]=u;
if(!son[u]) ans.push(0),bot[tp]=tim,build(rt[tp],dfn[tp],tim);
else dfs2(son[u],tp);
for(int i=fir[u],v;i;i=nxt[i]) if(!top[v=to[i]]) g[u].push(0),dfs2(v,v);
}
void pushdown(int i){if(t[i].tag) t[lc[i]].add(t[i].tag),t[rc[i]].add(t[i].tag),t[i].tag=0;}
void mdf(int i,int l,int r,int x,int y,int v){//b in [x,y] += v
if(x<=l&&r<=y) return t[i].add(v);
int mid=l+r>>1; pushdown(i);
if(x<=mid) mdf(lc[i],l,mid,x,y,v);
if(y>mid) mdf(rc[i],mid+1,r,x,y,v);
t[i]=t[lc[i]]+t[rc[i]];
}
void mdfa(int i,int l,int r,int x,int v){//a at x += v
if(l==r) {t[i].lx+=v,t[i].rx+=v,t[i].mx+=v,t[i].sa+=v; return;}
int mid=l+r>>1; pushdown(i);
x<=mid?mdfa(lc[i],l,mid,x,v):mdfa(rc[i],mid+1,r,x,v);
t[i]=t[lc[i]]+t[rc[i]];
}
void ins(int i,int l,int r,int x){//g changes, recalc.
if(l==r){
t[i].lx=g[ln[x]].top()+t[i].sa;
t[i].rx=t[i].lx+t[i].tag;
t[i].mx=t[i].rx+g[ln[x]].sec();
return;
}
int mid=l+r>>1; pushdown(i);
x<=mid?ins(lc[i],l,mid,x):ins(rc[i],mid+1,r,x);
t[i]=t[lc[i]]+t[rc[i]];
}
#define ERASE ans.erase(t[rt[tp]].mx)
#define PUSH ans.push(t[rt[tp]].mx)
void modify(int u,int v,int w){
int tp;
for(;top[u]!=top[v];u=fa[top[u]]){
if(dep[top[u]]<dep[top[v]]) swap(u,v);
tp=top[u];
ERASE; mdf(rt[tp],dfn[tp],bot[tp],dfn[tp],dfn[u],w); PUSH;
}
if(dep[u]<dep[v]) swap(u,v);
if(u!=v){
tp=top[u];
ERASE; mdf(rt[tp],dfn[tp],bot[tp],dfn[v]+1,dfn[u],w); PUSH;
u=v;
}//now u is LCA.
if(fa[tp=top[u]]) g[fa[tp]].erase(t[rt[tp]].lx);
ERASE; mdfa(rt[tp],dfn[tp],bot[tp],dfn[u],w); PUSH;
if(fa[tp]) g[fa[tp]].push(t[rt[tp]].lx);
for(u=fa[tp];u;u=fa[tp]){
if(fa[tp=top[u]]) g[fa[tp]].erase(t[rt[tp]].lx);
ERASE; ins(rt[tp],dfn[tp],bot[tp],dfn[u]); PUSH;
if(fa[tp]) g[fa[tp]].push(t[rt[tp]].lx);
}
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1,x,y;i<n;i++) scanf("%d%d",&x,&y),line(x,y),line(y,x);
dfs1(1,0),dfs2(1,1);
static int x[maxn],y[maxn],z[maxn]; char op[3];
for(int i=1,t;i<=m;i++){
if(scanf("%s",op),op[0]=='+') scanf("%d%d%d",&x[i],&y[i],&z[i]),modify(x[i],y[i],z[i]);
else scanf("%d",&t),modify(x[t],y[t],-z[t]);
printf("%lld\n",ans.top());
}
}