2.1
闲话
- 颓。
做题纪要
luogu P7840 「C.E.L.U-03」重构
-
多倍经验: [ABC359F] Tree Degree Optimization
-
按位拆平方贡献,优先队列辅助查询最小值。
-
由相关理论可知一定存在一种构造方案。
点击查看代码
struct node {ll du,val;bool operator < (const node &another) const{return val*(2*du+1)>another.val*(2*another.du+1);} }tmp; priority_queue<node>q; int main() { // #define Isaac #ifdef Isaacfreopen("in.in","r",stdin);freopen("out.out","w",stdout); #endifll n,x,ans=0,i;cin>>n;for(i=1;i<=n;i++){cin>>x;q.push((node){1,x});}for(i=1;i<=n-2;i++){tmp=q.top();q.pop();tmp.du++;q.push(tmp);}while(q.empty()==0){ans+=q.top().val*q.top().du*q.top().du;q.pop();}cout<<ans<<endl;return 0; }
[ABC266Ex] Snuke Panic (2D)
-
转移的限制条件为 \(\begin{cases} y_{j} \le y_{i} \\ t_{j} \le t_{i} \\ |x_{i}-x_{j}|+y_{i}-y_{j} \le x_{i}-x_{j} \end{cases}\) 。
-
将第三个条件的绝对值拆开后在满足限制条件一和三后一定满足条件二, \(CDQ\) 分治优化即可。
点击查看代码
const ll inf=0x3f3f3f3f3f3f3f3f; struct node {ll t,x,y,val,b,c,id; }q[100010]; ll f[100010],d[100010]; bool cmp1(node a,node b) {if(a.b!=b.b) return a.b>b.b;if(a.c!=b.c) return a.c>b.c;return a.y<b.y; } bool cmp2(node a,node b) {return a.c>b.c; } bool cmp3(node a,node b) {return a.id<b.id; } struct BIT {ll c[100010];ll lowbit(ll x){return (x&(-x));}void clear(){memset(c,-0x3f,sizeof(f));}void add(ll n,ll x,ll val){for(ll i=x;i<=n;i+=lowbit(i)) c[i]=max(c[i],val);}void del(ll n,ll x){for(ll i=x;i<=n;i+=lowbit(i)) c[i]=-inf;}ll getsum(ll x){ll ans=-inf;for(ll i=x;i>=1;i-=lowbit(i)) ans=max(ans,c[i]);return ans;} }T; void cdq(ll l,ll r) {if(l>=r) return;ll mid=(l+r)/2,x=0,y=0;cdq(l,mid);sort(q+l,q+mid+1,cmp2);sort(q+mid+1,q+r+1,cmp2);for(x=l,y=mid+1;y<=r;y++){for(;q[x].c>=q[y].c&&x<=mid;x++) T.add(d[0],q[x].y,f[q[x].id]);f[q[y].id]=max(f[q[y].id],T.getsum(q[y].y)+q[y].val);}x--;for(ll i=l;i<=x;i++) T.del(d[0],q[i].y);sort(q+mid+1,q+r+1,cmp3);cdq(mid+1,r); } int main() { // #define Isaac #ifdef Isaacfreopen("in.in","r",stdin);freopen("out.out","w",stdout); #endif ll n,m=0,ans=0,i;cin>>n;for(i=1;i<=n;i++) {m++;cin>>q[m].t>>q[m].x>>q[m].y>>q[m].val;d[m]=q[m].y;q[m].b=-q[m].x+q[m].y-q[m].t;q[m].c=q[m].x+q[m].y-q[m].t;if(q[m].c>0) m--;}sort(d+1,d+m+1); d[0]=unique(d+1,d+m+1)-(d+1);sort(q+1,q+m+1,cmp1); for(i=1;i<=m;i++) {q[i].y=lower_bound(d+1,d+1+d[0],q[i].y)-d;q[i].id=i;f[i]=q[i].val;}T.clear(); cdq(1,m);for(i=1;i<=m;i++) ans=max(ans,f[i]);cout<<ans<<endl;return 0; }
2.2
闲话
- 颓。
做题纪要
CF914E Palindromes in a Tree
-
考虑点分治。因字符集很小,状压维护方案数。
-
此时是一个形如根链加的形式,树上差分即可。
-
实现时可以最后再处理经过分治中心 \(rt\) 的答案,注意点对的去重。
点击查看代码
struct node {ll nxt,to; }e[400010]; ll head[200010],ans[200010],cnt=0; char s[200010]; void add(ll u,ll v) {cnt++;e[cnt].nxt=head[u];e[cnt].to=v;head[u]=cnt; } struct Divide_On_Tree {ll siz[200010],weight[200010],vis[200010],d[200010],cnt[(1<<20)+10],dis[200010],tmp[(1<<20)+10],center;queue<ll>q;void init(ll n){center=0;get_center(1,0,n);get_siz(center,0);divide(center);}void get_center(ll x,ll fa,ll n){siz[x]=1;weight[x]=0;for(ll i=head[x];i!=0;i=e[i].nxt){if(e[i].to!=fa&&vis[e[i].to]==0){get_center(e[i].to,x,n);siz[x]+=siz[e[i].to];weight[x]=max(weight[x],siz[e[i].to]);}}weight[x]=max(weight[x],n-siz[x]);if(weight[x]<=n/2) center=x;}void get_siz(ll x,ll fa){siz[x]=1;for(ll i=head[x];i!=0;i=e[i].nxt){if(e[i].to!=fa&&vis[e[i].to]==0){get_siz(e[i].to,x);siz[x]+=siz[e[i].to];}}}void get_dis(ll x,ll fa){d[x]=0; dis[x]=dis[fa]^(1<<(s[x]-'a'));cnt[dis[x]]++; q.push(dis[x]);for(ll i=head[x];i!=0;i=e[i].nxt){if(e[i].to!=fa&&vis[e[i].to]==0) get_dis(e[i].to,x);}} ll work(ll x,ll rt){ll sum=0,c;for(ll i=0;i<=20;i++){if(i==20) c=dis[x]^dis[rt];else c=dis[x]^dis[rt]^(1<<i);if(c==dis[rt]){ans[rt]++;d[x]++;}sum+=cnt[c]-tmp[c];d[x]+=cnt[c]-tmp[c];}return sum;}ll dfs1(ll x,ll fa,ll rt){ll sum=work(x,rt);for(ll i=head[x];i!=0;i=e[i].nxt){if(e[i].to!=fa&&vis[e[i].to]==0) sum+=dfs1(e[i].to,x,rt);}return sum;}void dfs2(ll x,ll fa,ll rt){for(ll i=head[x];i!=0;i=e[i].nxt){if(e[i].to!=fa&&vis[e[i].to]==0){dfs2(e[i].to,x,rt);d[x]+=d[e[i].to];}}if(x!=rt) ans[x]+=d[x];}void clear(ll x,ll fa,ll op){tmp[dis[x]]+=op;for(ll i=head[x];i!=0;i=e[i].nxt){if(e[i].to!=fa&&vis[e[i].to]==0) clear(e[i].to,x,op);}}void divide(ll x){ll sum=0;vis[x]=1; d[x]=0; dis[x]=1<<(s[x]-'a');for(ll i=head[x];i!=0;i=e[i].nxt){if(vis[e[i].to]==0) get_dis(e[i].to,x);}for(ll i=head[x];i!=0;i=e[i].nxt){if(vis[e[i].to]==0){clear(e[i].to,x,1);sum+=dfs1(e[i].to,x,x);clear(e[i].to,x,-1);}}ans[x]+=sum/2; dfs2(x,0,x);while(q.empty()==0){cnt[q.front()]=0; q.pop();}for(ll i=head[x];i!=0;i=e[i].nxt){if(vis[e[i].to]==0){center=0;get_center(e[i].to,x,siz[e[i].to]);get_siz(center,x);divide(center); }}} }D; int main() { // #define Isaac #ifdef Isaacfreopen("in.in","r",stdin);freopen("out.out","w",stdout); #endifll n,u,v,i;cin>>n;for(i=1;i<=n-1;i++){cin>>u>>v;add(u,v); add(v,u);}scanf("%s",s+1);D.init(n);for(i=1;i<=n;i++) cout<<ans[i]+1<<" ";return 0; }