传送门

\(Maximum\ Remaining\)

对于两个数\(a,b\),如果\(a=b\)没贡献,所以不妨假设\(a<b\),有\(a\%b=a\),而\(b\%a<a\)。综上,我们可以发现答案就是严格次大值

//minamoto
#include<bits/stdc++.h>
#define R register
#define fp(i,a,b) for(R int i=(a),I=(b)+1;i<I;++i)
#define fd(i,a,b) for(R int i=(a),I=(b)-1;i>I;--i)
#define go(u) for(int i=head[u],v=e[i].v;i;i=e[i].nx,v=e[i].v)
template<class T>inline bool cmin(T&a,const T&b){return a>b?a=b,1:0;}
using namespace std;
char buf[1<<21],*p1=buf,*p2=buf;
inline char getc(){return p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++;}
int read(){
R int res,f=1;R char ch;
while((ch=getc())>'9'||ch<'0')(ch=='-')&&(f=-1);
for(res=ch-'0';(ch=getc())>='0'&&ch<='9';res=res*10+ch-'0');
return res*f;
}
const int N=1e5+5;
int x,n,mx,mmx;
int main(){
// freopen("testdata.in","r",stdin);
n=read();
fp(i,1,n){
x=read();
if(x>mx)mmx=mx,mx=x;
else if(x<mx&&x>mmx)mmx=x;
}
printf("%d\n",mmx);
return 0;
}

\(Friend\ or\ Girlfriend\)

总共区间个数减去不包含的区间个数就可以了

//minamoto
#include<bits/stdc++.h>
#define R register
#define ll long long
#define fp(i,a,b) for(R int i=(a),I=(b)+1;i<I;++i)
#define fd(i,a,b) for(R int i=(a),I=(b)-1;i>I;--i)
#define go(u) for(int i=head[u],v=e[i].v;i;i=e[i].nx,v=e[i].v)
using namespace std;
char buf[1<<21],*p1=buf,*p2=buf;
inline char getc(){return p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++;}
int read(){
R int res,f=1;R char ch;
while((ch=getc())>'9'||ch<'0')(ch=='-')&&(f=-1);
for(res=ch-'0';(ch=getc())>='0'&&ch<='9';res=res*10+ch-'0');
return res*f;
}
int read(char *s){
R int len=0;R char ch;while(((ch=getc())>'z'||ch<'a'));
for(s[++len]=ch;(ch=getc())>='a'&&ch<='z';s[++len]=ch);
return s[len+1]='\0',len;
}
const int N=1e6+5;
char s[N],c;int n;ll res;
inline ll calc(R int x){return 1ll*x*(x+1)>>1;}
int main(){
// freopen("testdata.in","r",stdin);
for(int T=read();T;--T){
n=read(),read(s),c=getc(),res=calc(n);
s[0]=s[n+1]=c;
for(R int i=0,j=1;i<=n;i=j,j=i+1){
while(s[j]!=c)++j;
res-=calc(j-i-1);
}
printf("%lld\n",res);
}
return 0;
}

\(Fencing\)

每块菜地周围先放四个栅栏,然后把所有两块菜地相邻处的两个栅栏全拆了

//minamoto
#include<bits/stdc++.h>
#define R register
#define fp(i,a,b) for(R int i=(a),I=(b)+1;i<I;++i)
#define fd(i,a,b) for(R int i=(a),I=(b)-1;i>I;--i)
#define go(u) for(int i=head[u],v=e[i].v;i;i=e[i].nx,v=e[i].v)
using namespace std;
char buf[1<<21],*p1=buf,*p2=buf;
inline char getc(){return p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++;}
int read(){
R int res,f=1;R char ch;
while((ch=getc())>'9'||ch<'0')(ch=='-')&&(f=-1);
for(res=ch-'0';(ch=getc())>='0'&&ch<='9';res=res*10+ch-'0');
return res*f;
}
char sr[1<<21],z[20];int C=-1,Z=0;
inline void Ot(){fwrite(sr,1,C+1,stdout),C=-1;}
void print(R int x){
if(C>1<<20)Ot();if(x<0)sr[++C]='-',x=-x;
while(z[++Z]=x%10+48,x/=10);
while(sr[++C]=z[Z],--Z);sr[++C]='\n';
}
const int N=1e5+5;
struct node{int x,y;}p[N];
inline bool cmp1(const node &a,const node &b){return a.x==b.x?a.y<b.y:a.x<b.x;}
inline bool cmp2(const node &a,const node &b){return a.y==b.y?a.x<b.x:a.y<b.y;}
int n,m,k,res;
int main(){
// freopen("testdata.in","r",stdin);
for(int T=read();T;--T){
n=read(),m=read(),k=read(),res=(k<<2);
fp(i,1,k)p[i].x=read(),p[i].y=read();
sort(p+1,p+1+k,cmp1);
for(R int i=1,j=1;i<=k;++j,i=j){
while(j<=k&&p[j+1].x==p[i].x)++j;
fp(l,i,j-1)res-=(p[l+1].y-p[l].y==1)*2;
}
sort(p+1,p+1+k,cmp2);
for(R int i=1,j=1;i<=k;++j,i=j){
while(j<=k&&p[j+1].y==p[i].y)++j;
fp(l,i,j-1)res-=(p[l+1].x-p[l].x==1)*2;
}
printf("%d\n",res);
}
return 0;
}

\(Subtree\ Removal\)

显然没必要选了一个节点\(u\)之后再选它的祖先

记\(sum_u\)表示\(u\)的子树中节点权值之和。我们设\(dp_{u,0/1}\)考虑\(u\)的子树,\(0/1\)表示是否删去\(u\)的子树,所有被删去节点的权值之和加上\(k\times X\)的最小值,那么最终答案就是\(sum_1-\min\{dp_{1,0},dp_{1,1}\}\)

树形\(dp\)的过程的话,如果\(u\)删掉,显然它的子树里的点没必要删,所有\(dp_{u,0}=sum_u+x\)。如果\(u\)不删,那么子树里的点随便删不删,即\(dp_{u,1}=\sum_{(u,v)\in E}\min\{dp_{v,0},dp_{v,1}\}\)

//minamoto
#include<bits/stdc++.h>
#define R register
#define ll long long
#define fp(i,a,b) for(R int i=(a),I=(b)+1;i<I;++i)
#define fd(i,a,b) for(R int i=(a),I=(b)-1;i>I;--i)
#define go(u) for(int i=head[u],v=e[i].v;i;i=e[i].nx,v=e[i].v)
using namespace std;
char buf[1<<21],*p1=buf,*p2=buf;
inline char getc(){return p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++;}
int read(){
R int res,f=1;R char ch;
while((ch=getc())>'9'||ch<'0')(ch=='-')&&(f=-1);
for(res=ch-'0';(ch=getc())>='0'&&ch<='9';res=res*10+ch-'0');
return res*f;
}
char sr[1<<21],z[20];int C=-1,Z=0;
inline void Ot(){fwrite(sr,1,C+1,stdout),C=-1;}
void print(R int x){
if(C>1<<20)Ot();if(x<0)sr[++C]='-',x=-x;
while(z[++Z]=x%10+48,x/=10);
while(sr[++C]=z[Z],--Z);sr[++C]='\n';
}
const int N=1e5+5;
struct eg{int v,nx;}e[N<<1];int head[N],tot;
inline void add(R int u,R int v){e[++tot]={v,head[u]},head[u]=tot;}
ll sum[N],dp[N][2];int n,x;
void dfs(int u,int fa){
dp[u][0]=0;
go(u)if(v!=fa)dfs(v,u),sum[u]+=sum[v],dp[u][0]+=min(dp[v][0],dp[v][1]);
dp[u][1]=sum[u]+x;
}
int main(){
// freopen("testdata.in","r",stdin);
for(int T=read();T;--T){
n=read(),x=read();
fp(i,1,n)sum[i]=read();
for(R int i=1,u,v;i<n;++i)u=read(),v=read(),add(u,v),add(v,u);
dfs(1,0);
printf("%lld\n",sum[1]-min(dp[1][0],dp[1][1]));
memset(head,0,4*(n+1)),tot=0;
}
return 0;
}

\(Playing\ with\ Numbers\)

先说一个一般点的,对于固定的\(x\),\(kx\)在\(\bmod p\)意义下可以表示出所有是\(\gcd(p,x)\)的倍数的数

那么一条路径上能表示出的所有的数就是这条路径上所有节点点权的\(\gcd\)与叶子的\(m_i\)的\(\gcd\)的倍数,不妨记为\(d_i\)。那么答案就是\(m_i-d_i\)

//minamoto
#include<bits/stdc++.h>
#define R register
#define ll long long
#define fp(i,a,b) for(R int i=(a),I=(b)+1;i<I;++i)
#define fd(i,a,b) for(R int i=(a),I=(b)-1;i>I;--i)
#define go(u) for(int i=head[u],v=e[i].v;i;i=e[i].nx,v=e[i].v)
using namespace std;
char buf[1<<21],*p1=buf,*p2=buf;
inline char getc(){return p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++;}
ll read(){
R ll res,f=1;R char ch;
while((ch=getc())>'9'||ch<'0')(ch=='-')&&(f=-1);
for(res=ch-'0';(ch=getc())>='0'&&ch<='9';res=res*10+ch-'0');
return res*f;
}
char sr[1<<21],z[20];int C=-1,Z=0;
inline void Ot(){fwrite(sr,1,C+1,stdout),C=-1;}
void print(R ll x){
if(C>1<<20)Ot();if(x<0)sr[++C]='-',x=-x;
while(z[++Z]=x%10+48,x/=10);
while(sr[++C]=z[Z],--Z);sr[++C]=' ';
}
const int N=1e5+5;
struct eg{int v,nx;}e[N<<1];int head[N],tot;
inline void add(R int u,R int v){e[++tot]={v,head[u]},head[u]=tot;}
ll val[N],m[N],ans[N];int st[N],deg[N],top,n;
void dfs(int u,int fa){
if(deg[u]==1&&u!=1)st[++top]=u,ans[u]=m[u]-__gcd(m[u],val[u]);
go(u)if(v!=fa)val[v]=__gcd(val[v],val[u]),dfs(v,u);
}
int main(){
// freopen("testdata.in","r",stdin);
for(int T=read();T;--T){
n=read(),top=0;
for(R int i=1,u,v;i<n;++i)u=read(),v=read(),add(u,v),add(v,u),++deg[u],++deg[v];
fp(i,1,n)val[i]=read();fp(i,1,n)m[i]=read();
dfs(1,0);sort(st+1,st+1+top);
fp(i,1,top)print(ans[st[i]]);sr[++C]='\n';
memset(head,0,(n+1)<<2),memset(deg,0,(n+1)<<2);
tot=0;
}
return Ot(),0;
}

\(Kira\ Loves\ Palindromes\)

分成两种情况考虑,一个是两段长度相同,一个是两段长度不同

两段长度相同的话我们枚举一下\(s_1\)的末尾字符的位置,把末尾位置之后的那个串建个\(SAM\),然后再从后往前枚举\(s_1\)的开头,如果某一个时刻在\(SAM\)上找不到了就退出

两段长度不同的话,假设\(|s_1|>|s_2|\),那么\(s_1\)一定是由反过来的\(s_2\)加上一个回文串构成的。我们枚举这个回文串的末尾,把后面那一段建一个\(SAM\),然后再枚举回文串的开头,之后就和长度相同的情况一样了,因为回文串开头前面的位置就是需要的结尾位置

理论复杂度\(O(n^3)\),不过极限数据都能过……(本地测\(1000\)个\(a\)都没\(T\)),那就不管那么多了……

upd:据\(zzk\)巨巨说,理论复杂度应该是\(O({n\choose 3})\),大概\(10^8\),差不多能过……

//minamoto
#include<bits/stdc++.h>
#define R register
#define ll long long
#define fp(i,a,b) for(R int i=(a),I=(b)+1;i<I;++i)
#define fd(i,a,b) for(R int i=(a),I=(b)-1;i>I;--i)
#define go(u) for(int i=head[u],v=e[i].v;i;i=e[i].nx,v=e[i].v)
template<class T>inline bool cmax(T&a,const T&b){return a<b?a=b,1:0;}
using namespace std;
char buf[1<<21],*p1=buf,*p2=buf;
inline char getc(){return p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++;}
int read(char *s){
R int len=0;R char ch;while(((ch=getc())>'z'||ch<'a'));
for(s[++len]=ch;(ch=getc())>='a'&&ch<='z';s[++len]=ch);
return s[len+1]='\0',len;
}
const int N=2005;
char s[N],now[N];int p[N],ch[N][26],fa[N],l[N],sz[N];
ll res;int cnt=1,n,las=1;bool is[N];
inline int newnode(int len){return ++cnt,memset(ch[cnt],0,104),fa[cnt]=sz[cnt]=0,l[cnt]=len,cnt;}
void ins(int c){
int p=las,np=las=newnode(l[p]+1);++sz[np];
for(;p&&!ch[p][c];p=fa[p])ch[p][c]=np;
if(!p)fa[np]=1;
else{
int q=ch[p][c];
if(l[q]==l[p]+1)fa[np]=q;
else{
int nq=newnode(l[p]+1);
memcpy(ch[nq],ch[q],104);
fa[nq]=fa[q],fa[q]=fa[np]=nq;
for(;ch[p][c]==q;p=fa[p])ch[p][c]=nq;
}
}
}
int q[N],c[N];
void calc(){
fp(i,1,cnt)c[i]=0;
fp(i,1,cnt)++c[l[i]];
fp(i,1,cnt)c[i]+=c[i-1];
fd(i,cnt,1)q[c[l[i]]--]=i;
fd(i,cnt,1)sz[fa[q[i]]]+=sz[q[i]];
sz[1]=0;
}
void manacher(char *s){
int len=strlen(s+1);
fp(i,1,len)now[(i<<1)-1]='%',now[i<<1]=s[i];
now[len=(len<<1|1)]='%';
int pos=0,r=0;
fp(i,1,len){
p[i]=i<r?min(p[(pos<<1)-i],r-i):1;
while(i-p[i]>=1&&i+p[i]<=len&&now[i-p[i]]==now[i+p[i]])++p[i];
cmax(r,i+p[i])?pos=i:0;
}
}
int main(){
freopen("testdata.in","r",stdin);
n=read(s),manacher(s);
fp(i,1,n-1){
cnt=0,las=newnode(0);
fp(j,i+1,n)ins(s[j]-'a');
calc();
for(R int p=1,j=i;j;--j){
if(!ch[p][s[j]-'a'])break;
p=ch[p][s[j]-'a'],res+=sz[p];
}
}
fp(i,1,n-2){
cnt=0,las=newnode(0);
fd(j,i,1)ins(s[j]-'a');
calc();
fp(j,i+1,n)is[j]=0;
int qwq=(i+1)<<1;
fp(j,qwq,n<<1|1)j-qwq+1<=p[j]?is[((j<<1)-qwq)>>1]=1:0;
for(R int j=i+1,p=1;j<n;++j,p=1)if(is[j]){
fp(k,j+1,n){
if(!ch[p][s[k]-'a'])break;
p=ch[p][s[k]-'a'],res+=sz[p];
}
}
}
fd(i,n,3){
cnt=0,las=newnode(0);
fp(j,i,n)ins(s[j]-'a');
calc();
fd(j,i-1,1)is[j]=0;
int qwq=(i-1)<<1;
fd(j,qwq,1)qwq-j+1<=p[j]?is[((j<<1)-qwq)>>1]=1:0;
for(R int j=i-1,p=1;j>1;--j,p=1)if(is[j]){
fd(k,j-1,1){
if(!ch[p][s[k]-'a'])break;
p=ch[p][s[k]-'a'],res+=sz[p];
}
}
}
printf("%lld\n",res);
return 0;
}

\(Mininum\ XOR\ over\ Tree\)

类似于线段树合并,我们搞个\(trie\)树合并就可以了,复杂度\(O(n\log^2n)\)

//minamoto
#include<bits/stdc++.h>
#define R register
#define inf 0x3f3f3f3f
#define fp(i,a,b) for(R int i=(a),I=(b)+1;i<I;++i)
#define fd(i,a,b) for(R int i=(a),I=(b)-1;i>I;--i)
#define go(u) for(int i=head[u],v=e[i].v;i;i=e[i].nx,v=e[i].v)
template<class T>inline bool cmin(T&a,const T&b){return a>b?a=b,1:0;}
using namespace std;
char buf[1<<21],*p1=buf,*p2=buf;
inline char getc(){return p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++;}
int read(){
R int res,f=1;R char ch;
while((ch=getc())>'9'||ch<'0')(ch=='-')&&(f=-1);
for(res=ch-'0';(ch=getc())>='0'&&ch<='9';res=res*10+ch-'0');
return res*f;
}
char sr[1<<21],z[20];int C=-1,Z=0;
inline void Ot(){fwrite(sr,1,C+1,stdout),C=-1;}
void print(R int x){
if(C>1<<20)Ot();if(x<0)sr[++C]='-',x=-x;
while(z[++Z]=x%10+48,x/=10);
while(sr[++C]=z[Z],--Z);sr[++C]=' ';
}
const int N=2e5+5,M=(N<<6);
struct eg{int v,nx;}e[N<<1];int head[N],tot;
inline void add(R int u,R int v){e[++tot]={v,head[u]},head[u]=tot;}
int rt[N],ch[M][2],id[M],w[N],cnt,n,q,mx,du;
inline int newnode(){return id[++cnt]=inf,ch[cnt][0]=ch[cnt][1]=0,cnt;}
void ins(int p,int c,int u){
fd(i,19,0){
if(!ch[p][c>>i&1])ch[p][c>>i&1]=newnode();
p=ch[p][c>>i&1];
}
cmin(id[p],u);
}
void query(int p,int c){
mx=0;
fd(i,19,0)if(ch[p][c>>i&1^1])mx^=(1<<i),p=ch[p][c>>i&1^1];
else p=ch[p][c>>i&1];
du=id[p];
}
int merge(int x,int y){
if(!x||!y)return x|y;
int t=newnode();
ch[t][0]=merge(ch[x][0],ch[y][0]),
ch[t][1]=merge(ch[x][1],ch[y][1]),
id[t]=min(id[x],id[y]);
return t;
}
void dfs(int u,int fa){
rt[u]=newnode(),ins(rt[u],w[u],u);
go(u)if(v!=fa)dfs(v,u),rt[u]=merge(rt[u],rt[v]);
}
inline void clr(){tot=cnt=0;memset(head,0,(n+1)<<2);}
int main(){
// freopen("testdata.in","r",stdin);
for(int T=read();T;--T){
n=read(),q=read(),mx=du=0;
fp(i,1,n)w[i]=read();
for(R int i=1,u,v;i<n;++i)u=read(),v=read(),add(u,v),add(v,u);
dfs(1,0);
while(q--){
int u=read()^du,k=read()^mx;
query(rt[u],k);
print(du),print(mx),sr[C]='\n';
}
clr();
}
return Ot(),0;
}

\(Moving Rectangles (Challenge)\)

挑战题还是不做了……

\(Offer\ for\ Chef\)

想了几个小时之后,回去重新读题目突然发现

"in each query, the number of slices with toppings does not exceed 50"

也就是说有用的不超过\(50\)个,然而我一直按\(10^5\)在那里算……

不读题目太珂怕了……

有用的只有\(n=50\)个数字,我们考虑按位贪心,简单来说,我们需要判断最终的答案是否是\(s\)的超集(ps:如果\(i\)是\(j\)的子集,那么\(j\)就是\(i\)的超集)

设\(is[i][j]\)表示把前\(i\)个数分成\(j\)份,且每一份的和都是\(s\)的超集,是否可行。转移显然

//minamoto
#include<bits/stdc++.h>
#define R register
#define ll long long
#define fp(i,a,b) for(R int i=(a),I=(b)+1;i<I;++i)
#define fd(i,a,b) for(R int i=(a),I=(b)-1;i>I;--i)
#define go(u) for(int i=head[u],v=e[i].v;i;i=e[i].nx,v=e[i].v)
template<class T>inline bool cmax(T&a,const T&b){return a<b?a=b,1:0;}
using namespace std;
char buf[1<<21],*p1=buf,*p2=buf;
inline char getc(){return p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++;}
ll read(){
R ll res,f=1;R char ch;
while((ch=getc())>'9'||ch<'0')(ch=='-')&&(f=-1);
for(res=ch-'0';(ch=getc())>='0'&&ch<='9';res=res*10+ch-'0');
return res*f;
}
char sr[1<<21],z[20];int C=-1,Z=0;
inline void Ot(){fwrite(sr,1,C+1,stdout),C=-1;}
void print(R ll x){
if(C>1<<20)Ot();if(x<0)sr[++C]='-',x=-x;
while(z[++Z]=x%10+48,x/=10);
while(sr[++C]=z[Z],--Z);sr[++C]='\n';
}
const int N=1e5+5;
ll a[N],sum[55],res;int n,k,q,x,top;bool is[55][55];
bool ck(ll s){
memset(is,0,sizeof(is));
is[0][0]=1;
fp(i,0,top-1)fp(j,0,k-1)if(is[i][j]){
fp(l,i+1,top)if(((sum[l]-sum[i])&s)==s)is[l][j+1]=1;
}
return is[top][k];
}
int main(){
// freopen("testdata.in","r",stdin);
n=read();
fp(i,1,n)a[i]=read();
q=read();
while(q--){
top=0,k=read();
fp(i,1,n){
x=read();
if(x)sum[++top]=a[i]*x;
}
fp(i,1,top)sum[i]+=sum[i-1];
if(k>top)sr[++C]='0',sr[++C]='\n';
else{
res=0;
fd(i,59,0)if(ck(res|(1ll<<i)))res|=(1ll<<i);
print(res);
}
}
return Ot(),0;
}

\(Edgy\)

先考虑暴力,我们判断一下该怎么数纯色子树

因为每一个纯色子树的\(LCA\)都是唯一的,我们可以在\(LCA\)处计数。设这棵纯色子树的\(LCA\)为\(u\),\(u\)的父亲到它的边的颜色为\(c\),如果\(u\)到儿子的边中有一条的颜色不为\(c\),那么就要\(++ans\)。即使有多条颜色不为\(c\)也只加一次,因为这些颜色不同的边是在同一个纯色子树中的。特别的,记\(1\)的父亲边的颜色为\(-1\)

这样我们可以打出一个暴力,首先把路径修改拆成两次节点到根的链修改,然后直接暴力修改即可。如果在随机数据下,树高是期望\(O(\log n)\)的,复杂度为\(O(n\log n)\)

然而这样显然是\(gg\)的

我们考虑树剖

先假设\(u\)和\(u\)的重儿子都要被修改。如果\(u\)和\(son[u]\)的颜色不同,那么修改之后\(u\)的贡献并不会变。如果\(u\)的轻儿子中两种颜色都有,或者根本没有轻儿子,那么修改之后\(u\)的贡献也不会变

综上,对于\(u\)和\(son[u]\)都要被修改的情况,\(u\)的贡献会变化,当且仅当\(u\)存在轻儿子,且\(u\)的所有轻儿子颜色相同,并且\(u\)和\(son[u]\)颜色相同。如果之前\(u\)的贡献为\(0\),修改之后为\(1\)。之前为\(1\),修改之后就为\(0\)。不满足这些条件的节点都不需要考虑了

我们可以用线段树来维护,记\(sz[0]\)表示区间内贡献为\(0\)的节点个数,\(sz[1]\)表示区间内贡献为\(1\)的节点个数。每一次对一条重链的影响就相当于对一个区间取反,也就是说对于每一个区间\(swap(sz[0],sz[1])\),打懒标记就可以了。顺便修改之后要及时维护答案

接下来是\(u\)要修改,\(son[u]\)不需要修改的情况,也就是说我们切换了重链。设\(v\)前一条重链的顶端,也就是\(fa[v]=u\),那么\(v\)更新之后,“\(u\)的所有轻儿子颜色是否相同”这个条件有可能发生变化,而且\(u\)也被更新,所以“\(u\)和\(son[u]\)的颜色是否相同”这个条件也会发生变化。在线段树上更新就好了

顺带一提,我们在线段树上维护的只有“被链修改之后会改变贡献的点”的贡献,其它的贡献要另算。也就是说\(u\)和\(son[u]\)颜色不同,\(u\)的轻儿子中两种颜色都有的情况,线段树上是没有的,我们要自己维护

细节巨多,调了整整一个上午……

//minamoto
#include<bits/stdc++.h>
#define inline __attribute__((always_inline))
#define R register
#define fp(i,a,b) for(R int i=(a),I=(b)+1;i<I;++i)
#define fd(i,a,b) for(R int i=(a),I=(b)-1;i>I;--i)
#define go(u) for(int i=head[u],v=e[i].v;i;i=e[i].nx,v=e[i].v)
using namespace std;
char buf[1<<21],*p1=buf,*p2=buf;
inline char getc(){return p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++;}
int read(){
R int res,f=1;R char ch;
while((ch=getc())>'9'||ch<'0')(ch=='-')&&(f=-1);
for(res=ch-'0';(ch=getc())>='0'&&ch<='9';res=res*10+ch-'0');
return res*f;
}
char sr[1<<21],z[20];int C=-1,Z=0;
inline void Ot(){fwrite(sr,1,C+1,stdout),C=-1;}
void print(R int x){
if(C>1<<20)Ot();if(x<0)sr[++C]='-',x=-x;
while(z[++Z]=x%10+48,x/=10);
while(sr[++C]=z[Z],--Z);sr[++C]='\n';
}
const int N=1e5+5;
struct eg{int v,nx,w;}e[N<<1];int head[N],tot;
inline void add(R int u,R int v,R int w){e[++tot]={v,head[u],w},head[u]=tot;}
inline void swap(R int &x,R int &y){x^=y^=x^=y;}
int col[N],bl[N],top[N],dfn[N],rk[N],sz[N],son[N],dep[N],fa[N],cnt,res;
int sum[N][2];bool ok[N],b[N];
void dfs1(int u,int id){
sz[u]=1,dep[u]=dep[fa[u]]+1,bl[u]=id;
go(u)if(v!=fa[u]){
col[v]=e[i].w,fa[v]=u,dfs1(v,id),sz[u]+=sz[v];
if(sz[v]>sz[son[u]])son[u]=v;
}
}
void dfs2(int u,int t){
rk[dfn[u]=++cnt]=u,top[u]=t,sum[u][0]=sum[u][1]=0;
if(!son[u])return;
dfs2(son[u],t);
go(u)if(!top[v])dfs2(v,v),++sum[u][col[v]];
if((!sum[u][0]||!sum[u][1])&&(sum[u][0]+sum[u][1])&&col[u]==col[son[u]])
ok[u]=1,b[u]=(sum[u][col[u]^1]!=0);
if(sum[u][0]&&sum[u][1]||col[u]!=col[son[u]])++res;
}
struct node{
node *lc,*rc;int sz[2],c,r;
inline void ppd(){r^=1,c^=1,swap(sz[0],sz[1]);}
inline void pd(){if(r)lc->ppd(),rc->ppd(),r=0;}
inline void upd(){sz[0]=lc->sz[0]+rc->sz[0],sz[1]=lc->sz[1]+rc->sz[1];}
}pool[N<<2],*rt,*pp=pool;
inline node* newnode(){pp->lc=pp->rc=NULL,pp->sz[0]=pp->sz[1]=pp->c=pp->r=0;return pp++;}
void build(node* &p,int l,int r){
p=newnode();
if(l==r){
p->c=col[rk[l]];
if(ok[rk[l]])p->sz[b[rk[l]]]=1;
res+=p->sz[1];
return;
}
int mid=(l+r)>>1;
build(p->lc,l,mid),build(p->rc,mid+1,r);
p->upd();
}
int query(node *p,int l,int r,int x){
if(l==r)return p->c;
int mid=(l+r)>>1;p->pd();
return x<=mid?query(p->lc,l,mid,x):query(p->rc,mid+1,r,x);
}
void update(node *p,int l,int r,int x,int d){
if(l==r){
res-=p->sz[1];
p->sz[0]=p->sz[1]=0;
if(d>=0)p->sz[d]=1;
res+=p->sz[1];
return;
}
int mid=(l+r)>>1;p->pd();
x<=mid?update(p->lc,l,mid,x,d):update(p->rc,mid+1,r,x,d);
p->upd();
}
void rev(node *p,int l,int r,int ql,int qr){
if(ql<=l&&qr>=r)return res-=p->sz[1],res+=p->sz[0],p->ppd(),void();
int mid=(l+r)>>1;p->pd();
if(ql<=mid)rev(p->lc,l,mid,ql,qr);
if(qr>mid)rev(p->rc,mid+1,r,ql,qr);
p->upd();
}
int n,q;
inline void clr(){fp(i,1,n)head[i]=top[i]=son[i]=ok[i]=b[i]=0;tot=cnt=0;pp=pool;}
void change(int u){
int las=-1;
while(u!=1){
if(son[u]){
int c=query(rt,1,n-1,dfn[u]);
int cc=query(rt,1,n-1,dfn[son[u]]);
if(c!=cc||(sum[u][0]&&sum[u][1]))--res;
if(las>=0)--sum[u][las],++sum[u][las^1];
c^=1;
if(c!=cc||(sum[u][0]&&sum[u][1]))++res;
if((!sum[u][0]||!sum[u][1])&&(sum[u][0]+sum[u][1])&&c==cc)
update(rt,1,n-1,dfn[u],sum[u][c^1^1]!=0);
else update(rt,1,n-1,dfn[u],-1);
}
rev(rt,1,n-1,dfn[top[u]],dfn[u]);
u=top[u];
las=query(rt,1,n-1,dfn[u])^1;
u=fa[u];
}
if(las>=0)--sum[u][las],++sum[u][las^1];
}
int main(){
// freopen("testdata.in","r",stdin);
// freopen("testdata.out","w",stdout);
for(int T=read();T;--T){
n=read(),res=0,sum[1][0]=sum[1][1]=0;
for(R int i=1,u,v,w;i<n;++i)u=read(),v=read(),w=read(),add(u,v,w),add(v,u,w);
go(1)fa[v]=1,col[v]=e[i].w,dfs1(v,v),++sum[1][col[v]];
top[1]=1;go(1)dfs2(v,v);
res+=(sum[1][0]!=0)+(sum[1][1]!=0);
build(rt,1,n-1);
q=read();
while(q--){
int u=read(),v=read();
res-=(sum[1][0]!=0)+(sum[1][1]!=0);
change(u),change(v);
res+=(sum[1][0]!=0)+(sum[1][1]!=0);
print(res);
}
clr();
}
return Ot(),0;
}

\(Sonya\ and\ Queries\)

等我先学完\(ETT\)再回来填坑\(QAQ\)

CodeChef April Challenge 2019题解的更多相关文章

  1. Codechef April Challenge 2019 游记

    Codechef April Challenge 2019 游记 Subtree Removal 题目大意: 一棵\(n(n\le10^5)\)个结点的有根树,每个结点有一个权值\(w_i(|w_i\ ...

  2. CodeChef March Challenge 2019题解

    传送门 \(CHNUM\) 显然正数一组,负数一组 for(int T=read();T;--T){ n=read(),c=d=0; fp(i,1,n)x=read(),x>0?++c:++d; ...

  3. Codechef April Challenge 2019 Division 2

    Maximum Remaining 题意:给n个数,取出两个数$a_{i}$,$a_{j}$,求$a_{i}\% a_{j}$取模的最大值 直接排个序,第二大(严格的第二大)模第一大就是答案了. #i ...

  4. CodeChef November Challenge 2019 Division 1题解

    传送门 AFO前的最后一场CC了--好好打吧-- \(SIMGAM\) 偶数行的必定两人平分,所以只要抢奇数行中间那个就行了 这题怎么被爆破了 //quming #include<bits/st ...

  5. Codechef July Challenge 2019 Division 1题解

    题面 \(CIRMERGE\) 破环成链搞个裸的区间\(dp\)就行了 //quming #include<bits/stdc++.h> #define R register #defin ...

  6. Code Chef February Challenge 2019题解

    传送门 \(HMAPPY2\) 咕 话说这题居然卡\(scanf\)的么??? int T;cin>>T; while(T--){ cin>>n>>a>> ...

  7. Codechef November Challenge 2019 Division 1

    Preface 这场CC好难的说,后面的都不会做QAQ 还因为不会三进制位运算卷积被曲明姐姐欺负了,我真是太菜了QAQ PS:最后还是狗上了六星的说,期待两(三)场之内可以上七星 Physical E ...

  8. Codechef October Challenge 2019 Division 1

    Preface 这次CC难度较上两场升高了许多,后面两题都只能借着曲明姐姐和jz姐姐的仙气来做 值得一提的是原来的F大概需要大力分类讨论,结果我写了一大半题目就因为原题被ban了233 最后勉强涨了近 ...

  9. Codechef September Challenge 2019 Division 2

    Preface 这确实应该是我打过的比较水的CC了(其实就打过两场) 但由于我太弱了打的都是Div2,所以会认为上一场更简单,其实上一场Div的数据结构是真的毒 好了废话不多说快速地讲一下 A Eas ...

随机推荐

  1. Git---远程仓库之从远程仓库克隆03

    远程仓库之添加远程仓库02我们讲了先有本地库,后有远程库,如何关联远程库. 现在假设我们从零开发,那么最好的方式是先创建远程库,然后,从远程库克隆. 首先,登录GitHub,创建一个新的仓库,名字叫g ...

  2. Unity XLua 官方案例学习

    1. Helloworld using UnityEngine; using XLua; public class Helloworld : MonoBehaviour { // Use this f ...

  3. MVC4中压缩和合并js文件和样式文件

    1.在App_Start文件夹中BundleConfig.cs类中添加相应的文件 1.1bundles.Add(new ScriptBundle("~/bundles/adminJs&quo ...

  4. Matlab中插值函数汇总(下)

    Matlab中插值函数汇总分上下两个部分,主要整合自matlabsky论坛dynamic发表于2009-2-21 21:53:26 的主题帖,以及豆丁网rickoon上传的教材第8章<插值,拟合 ...

  5. python简单爬虫(一)

    学习python前纠结了下,到底是应该一个个知识点吃透,然后写些小程序.还是应该快速掌握基础语法,快速实践.思考后认为前者这么学习速度真心不高,于是花2天时间看了下python3的语法,虽然很多都不明 ...

  6. springMVC框架的作用

    springMVC:是一个表现层框架 作用:就是从请求中接收传入的参数 将处理后的结果数据返回给页面展示

  7. ADO.NET DataTable的复制(clone)

    using (SqlConnection conn = new SqlConnection("Data Source=.;Initial Catalog=test;Integrated Se ...

  8. Interceptor for {http://cxf.liuyang.com/}IHiServiceService has thrown exception, unwinding now org.apache.cxf.binding.soap.SoapFault: Error reading XMLStreamReader.

    Jquery同域访问:客户端连接服务器访问跨域访问:通过本地html文档,浏览器点击开访问(jquery不支持此访问) 用域名的方式访问http://localhost:8080/CXF_09_jqu ...

  9. SCI EI期刊

    coming soon 关键字:Computer Vision, Computing, Image, Intelligence, IEEE, Compution <Journal of Expe ...

  10. canvas基础API

    1.路径绘图: 把“钢笔”移动到画布的某个位置上 ctx.moveTo(x,y) 把“钢笔”连线到画布的某个位置上 ctx.lineTo(x,y) 描边路径的api ctx.stroke() 填充路径 ...