没拿到D类名额
NOI2016我去不了了
仔细一算,发现NOIP要是考到500+也许就拿到D类了吧
AFO
首先树同构我是写过的……就是BJOI那题
然后图同构我是不会的……
然后就花了点头盾看了题解。
原来和树Hash差不多,只要进行迭代就好了
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
const int M=4005,N=205;
const long long P1=808080808080803ll,P2=888888888888887ll;
int n,m,hA[N],hB[N],enA,enB,test;
long long valA_1[N],valB_1[N],valA_2[N],valB_2[N],tmp1[N],tmp2[N],Vt1[N],Vt2[N];
struct Edge{
int b,next;
}eA[M<<1],eB[M<<1];
void AddEdgeA(int sa,int sb){
eA[++enA].b=sb;
eA[enA].next=hA[sa];
hA[sa]=enA;
}
void AddEdgeB(int sa,int sb){
eB[++enB].b=sb;
eB[enB].next=hB[sa];
hB[sa]=enB;
}
void Solve_A(){
for(int i=1;i<=n;i++){
int cnt=0;
for(int j=hA[i];j;j=eA[j].next){
int v=eA[j].b;cnt++;
tmp1[cnt]=valA_1[v];
tmp2[cnt]=valA_2[v];
}
sort(tmp1+1,tmp1+cnt+1);
sort(tmp2+1,tmp2+cnt+1);
long long Ha1=0,Ha2=0;
for(int j=1;j<=cnt;j++){Ha1=(Ha1*233ll+tmp1[j])%P1;Ha2=(Ha2*666ll+tmp2[j])%P2;}
Vt1[i]=Ha1;Vt2[i]=Ha2;
}
for(int i=1;i<=n;i++){valA_1[i]=Vt1[i];valA_2[i]=Vt2[i];}
}
void Solve_B(){
for(int i=1;i<=n;i++){
int cnt=0;
for(int j=hB[i];j;j=eB[j].next){
int v=eB[j].b;cnt++;
tmp1[cnt]=valB_1[v];
tmp2[cnt]=valB_2[v];
}
sort(tmp1+1,tmp1+cnt+1);
sort(tmp2+1,tmp2+cnt+1);
long long Ha1=0,Ha2=0;
for(int j=1;j<=cnt;j++){Ha1=(Ha1*233ll+tmp1[j])%P1;Ha2=(Ha2*666ll+tmp2[j])%P2;}
Vt1[i]=Ha1;Vt2[i]=Ha2;
}
for(int i=1;i<=n;i++){valB_1[i]=Vt1[i];valB_2[i]=Vt2[i];}
}
void Solve(){
scanf("%d %d",&n,&m);
memset(hA,0,sizeof(hA));
memset(hB,0,sizeof(hB));
enA=0;enB=0;
for(int i=1;i<=m;i++){
int u,v;
scanf("%d %d",&u,&v);
AddEdgeA(u,v);AddEdgeA(v,u);
}
for(int i=1;i<=m;i++){
int u,v;
scanf("%d %d",&u,&v);
AddEdgeB(u,v);AddEdgeB(v,u);
}
for(int i=1;i<=n;i++)valA_1[i]=valA_2[i]=valB_1[i]=valB_2[i]=1;
for(int i=1;i<=n;i++)Solve_A();
for(int i=1;i<=n;i++)Solve_B();
sort(valA_1+1,valA_1+n+1);
sort(valA_2+1,valA_2+n+1);
sort(valB_1+1,valB_1+n+1);
sort(valB_2+1,valB_2+n+1);
int flag=1;
for(int i=1;i<=n;i++)if(valA_1[i]!=valB_1[i] || valA_2[i]!=valB_2[i]){puts("NO");flag=0;break;}
if(flag)puts("YES");
}
int main(){
freopen("1676.in","r",stdin);
freopen("1676.out","w",stdout);
scanf("%d",&test);
while(test--)Solve();
return 0;
}
维护相等的关系要用并查集
而对于不等关系,因为没有传递性我们用一个set来维护
合并时根据set的大小启发式合并就好了
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<set>
using namespace std;
const int N=200005;
int n,f[N],b[N],cnt,id[N];
set<int> S[N];
struct Save{
int a,b,p;
}sav[N];
int Find(int x){return f[x]==x?x:f[x]=Find(f[x]);}
void Union(int x,int y){
if(x==y)return;
if(S[x].size()>S[y].size())swap(x,y);
for(set<int>::iterator i=S[x].begin();i!=S[x].end();i++)S[y].insert(Find(*i));
f[x]=y;
}
int main(){
freopen("1515.in","r",stdin);
freopen("1515.out","w",stdout);
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d %d %d",&sav[i].a,&sav[i].b,&sav[i].p);
b[++cnt]=sav[i].a;f[cnt]=cnt;
b[++cnt]=sav[i].b;f[cnt]=cnt;
}
sort(b+1,b+cnt+1);
cnt=unique(b+1,b+cnt+1)-b-1;
for(int i=1;i<=n;i++){
sav[i].a=Find(lower_bound(b+1,b+cnt+1,sav[i].a)-b);
sav[i].b=Find(lower_bound(b+1,b+cnt+1,sav[i].b)-b);
if(sav[i].p){
if(S[sav[i].b].find(sav[i].a)!=S[sav[i].b].end() || S[sav[i].a].find(sav[i].b)!=S[sav[i].a].end())puts("NO");
else puts("YES"),Union(sav[i].a,sav[i].b);
}
else {
if(sav[i].a==sav[i].b)puts("NO");
else puts("YES"),S[sav[i].a].insert(sav[i].b),S[sav[i].b].insert(sav[i].a);
}
}
return 0;
}
首先最大值最小显然是二分
然后就是混合图的欧拉回路
首先我们对于无向图的欧拉回路可以记录点的度数(度数为偶数),有向图的欧拉回路则是Abs(入度-出度)为偶数时有欧拉回路
那么混合图怎么办?网络流判定就好了。
为了方便和卡常数我所有的流量都除以了2.
我们把无向边随便定个方向再计算出度和入度,然后再连接一条反向边流量为1表示可以返回(因为可能无向边定的方向是相反的,那么对入度和出度会造成总共2的影响,所以连接流量为1)
然后对于入度>出度的点,我们连接源点到这个点,流量是入度减去出度再除以2.
否则连接这个点到汇点,流量是出度减去入度再除以2.
那么判断这个图是否满流就知道能不能形成欧拉回路了(因为欧拉回路每条边都经过所以一定满流)
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<queue>
#include<algorithm>
using namespace std;
const int N=2005,INF=2100000000;
int n,m,h[N],level[N],S,T,cur[N],in[N],out[N],en;
queue<int> Q;
struct E{
int u,v,a,b;
}es[N];
struct Edge{
int b,f,back,next;
}e[N<<2];
int Abs(int x){return x>0?x:-x;}
void AddEdge(int sa,int sb,int sc){
e[++en].b=sb;
e[en].f=sc;
e[en].back=en+1;
e[en].next=h[sa];
h[sa]=en;
swap(sa,sb);
e[++en].b=sb;
e[en].f=0;
e[en].back=en-1;
e[en].next=h[sa];
h[sa]=en;
}
int BFS(){
memset(level,0,sizeof(level));
Q.push(S);
level[S]=1;
while(!Q.empty()){
int u=Q.front();
Q.pop();
for(int i=h[u];i;i=e[i].next){
int v=e[i].b;
if(level[v] || !e[i].f)continue;
level[v]=level[u]+1;
Q.push(v);
}
}
return level[T];
}
int DFS(int u,int flow){
if(u==T)return flow;
int f=flow;
for(int &i=cur[u];i;i=e[i].next){
int v=e[i].b,fl;
if(level[v]==level[u]+1 && e[i].f && (fl=DFS(v,min(f,e[i].f)))){
f-=fl;
e[i].f-=fl;
e[e[i].back].f+=fl;
if(f==0)return flow;
}
}
return flow-f;
}
int Dinic(){
int ans=0;
while(BFS()){for(int i=1;i<=n+2;i++)cur[i]=h[i];ans+=DFS(S,INF);}
return ans;
}
bool Odd(){for(int i=1;i<=n;i++)if(Abs(in[i]-out[i])&1)return 1;return 0;}
bool Test(int k){
memset(in,0,sizeof(in));
memset(out,0,sizeof(out));
memset(h,0,sizeof(h));
en=0;S=n+1;T=n+2;
for(int i=1;i<=m;i++){
if(es[i].a<=k && es[i].b<=k)AddEdge(es[i].v,es[i].u,1),out[es[i].u]++,in[es[i].v]++;
else if(es[i].a<=k)out[es[i].u]++,in[es[i].v]++;
else if(es[i].b<=k)out[es[i].v]++,in[es[i].u]++;
else return 0;
}
if(Odd())return 0;
int ank=0;
for(int i=1;i<=n;i++){
if(in[i]>out[i])AddEdge(S,i,in[i]-out[i]>>1),ank+=in[i]-out[i]>>1;
if(in[i]<out[i])AddEdge(i,T,out[i]-in[i]>>1);
}
return Dinic()==ank;
}
int main(){
freopen("2095.in","r",stdin);
freopen("2095.out","w",stdout);
scanf("%d %d",&n,&m);
for(int i=1;i<=m;i++)scanf("%d %d %d %d",&es[i].u,&es[i].v,&es[i].a,&es[i].b);
int l=1,r=1000,ans=0;
while(l<=r){
int mid=l+r>>1;
if(Test(mid))r=mid-1,ans=mid;
else l=mid+1;
}
if(!ans)puts("NIE");
else printf("%d\n",ans);
return 0;
}
这题一眼FFT,注意$a_i$的范围也是10W左右(题目没写)
怎么做:构建指数型母函数$F(x)=a_0+a_1*x+...+a_k*x^k$,其中$a_i$是长度为$i$的木棍个数,指数就是长度
那么卷积一次后顺着扫描一遍,边扫描边统计当前有多少种组合情况,注意偶数会多算一倍需要减掉
那么不能组成的概率就是当前的组合种数乘以当前长度的木棍数
最后答案只需要用1减一下就好了
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
const int N=262144;
const double Pi=acos(-1);
int n,Step,Rev[N],tn,test,nn,Su[N];
struct Complex{
double a,b;
Complex(){}
Complex(double sa,double sb){a=sa;b=sb;}
friend Complex operator+(Complex A,Complex B){return Complex(A.a+B.a,A.b+B.b);}
friend Complex operator-(Complex A,Complex B){return Complex(A.a-B.a,A.b-B.b);}
friend Complex operator*(Complex A,Complex B){return Complex(A.a*B.a-A.b*B.b,A.b*B.a+B.b*A.a);}
}A[N];
void FFT(Complex *r,int flag){
for(int i=0;i<n;i++)if(i<Rev[i])swap(r[i],r[Rev[i]]);
for(int k=1;k<n;k<<=1){
Complex wk=Complex(cos(Pi/k),flag*sin(Pi/k));
for(int i=0;i<n;i+=k<<1){
Complex wkj=Complex(1.0,0.0);
for(int j=0;j<k;j++){
Complex x=r[i+j],y=r[i+j+k]*wkj;
r[i+j]=x+y;
r[i+j+k]=x-y;
wkj=wkj*wk;
}
}
}
if(flag==-1)for(int i=0;i<n;i++)r[i].a/=n;
}
int main(){
freopen("3513.in","r",stdin);
freopen("3513.out","w",stdout);
scanf("%d",&test);
while(test--){
scanf("%d",&tn);nn=0;Rev[0]=0;
memset(Su,0,sizeof(Su));
for(int i=1;i<=tn;i++){int x;scanf("%d",&x);Su[x]++;nn=max(x,nn);}
nn++;
nn<<=1;
for(n=1,Step=0;n<nn;n<<=1,Step++);
nn>>=1;
for(int i=0;i<n;i++)Rev[i]=(Rev[i>>1]>>1)|((i&1)<<(Step-1));
for(int i=0;i<n;i++)A[i]=Complex(Su[i],0.0);
FFT(A,1);
for(int i=0;i<n;i++)A[i]=A[i]*A[i];
FFT(A,-1);
long long ans=0,tot=1ll*tn*(tn-1)*(tn-2)/6,can=0;
for(int i=0;i<=nn;i++){
can+=(long long)(A[i].a+0.5);
if(!(i%2))can-=Su[i/2];
if(!Su[i])continue;
ans+=Su[i]*can;
}
ans>>=1;
printf("%.7lf\n",1.0-1.0*ans/tot);
}
return 0;
}
首先你会发现这是一个最短路
然后你会发现边数太多了
然后就不会了
hzwer教导我们:不连边也能跑最短路
具体就是设定一个高度不断下降,像分层图那么搞就可以了
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<queue>
#include<algorithm>
using namespace std;
const int N=155,INF=1000000000,dx[]={1,-1,0,0,0},dy[]={0,0,-1,1,0};
int n,m,A[N][N],B[N][N],X[5],Y[5],D[N][N][N<<1],ans=INF,flag,num,a1,a2,b1,b2,c1,c2;
bool vis[N][N][N<<1];
struct Data{
int v,x,y,s;
Data(int vs,int xs,int ys,int ss){v=vs;x=xs;y=ys;s=ss;}
friend bool operator<(Data A,Data B){return A.v>B.v;}
};
priority_queue<Data> PQ;
void Dijkstra(int Xs,int Ys){
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
for(int k=0;k<=num;k++){
D[i][j][k]=INF;
vis[i][j][k]=0;
}
}
}
D[Xs][Ys][B[Xs][Ys]]=A[Xs][Ys];
while(!PQ.empty())PQ.pop();
vis[Xs][Ys][0]=1;
PQ.push(Data(A[Xs][Ys],Xs,Ys,B[Xs][Ys]));
while(!PQ.empty() && !(vis[X[1]][Y[1]][0] && vis[X[2]][Y[2]][0] && vis[X[3]][Y[3]][0])){
Data u=PQ.top();PQ.pop();
if(vis[u.x][u.y][u.s])continue;
vis[u.x][u.y][u.s]=1;
if(u.s){
for(int i=0;i<5;i++){
int nx=u.x+dx[i],ny=u.y+dy[i];
if(nx<1 || nx>n || ny<1 || ny>m || vis[nx][ny][u.s-1])continue;
if(u.v<D[nx][ny][u.s-1]){
D[nx][ny][u.s-1]=u.v;
PQ.push(Data(u.v,nx,ny,u.s-1));
}
}
}
else {
if(D[u.x][u.y][B[u.x][u.y]]>u.v+A[u.x][u.y]){
D[u.x][u.y][B[u.x][u.y]]=u.v+A[u.x][u.y];
PQ.push(Data(D[u.x][u.y][B[u.x][u.y]],u.x,u.y,B[u.x][u.y]));
}
}
}
}
int main(){
freopen("2143.in","r",stdin);
freopen("2143.out","w",stdout);
scanf("%d %d",&n,&m);num=n+m-2;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++)scanf("%d",&B[i][j]),B[i][j]=min(B[i][j],max(num-i-j,i+j-2));
}
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++)scanf("%d",&A[i][j]);
}
for(int i=1;i<=3;i++)scanf("%d %d",&X[i],&Y[i]);
Dijkstra(X[1],Y[1]);a1=D[X[2]][Y[2]][0];a2=D[X[3]][Y[3]][0];
Dijkstra(X[2],Y[2]);b1=D[X[1]][Y[1]][0];b2=D[X[3]][Y[3]][0];
Dijkstra(X[3],Y[3]);c1=D[X[1]][Y[1]][0];c2=D[X[2]][Y[2]][0];
if(ans>b1+c1)ans=b1+c1,flag=0;
if(ans>a1+c2)ans=a1+c2,flag=1;
if(ans>a2+b2)ans=a2+b2,flag=2;
if(ans==INF)puts("NO");
else {printf("%c\n%d\n",'X'+flag,ans);}
return 0;
}
dfs判定一下就没了
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
const int N=20005;
const long double eps=1e-8;
int t,n,m,h[N],vis[N],en,flag;
long double dep[N];
bool d[N];
struct Edge{
int b,next;
long double l1,l2;
bool l;
}e[N];
void AddEdge(int sa,int sb,int sc,int sd,bool se){
e[++en].b=sb;
e[en].l1=sc;
e[en].l2=sd;
e[en].l=se;
e[en].next=h[sa];
h[sa]=en;
}
void DFS(int u,int fa){
vis[u]=1;
for(int i=h[u];i && !flag;i=e[i].next){
int v=e[i].b;
if(v==fa)continue;
if(!vis[v]){
d[v]=(d[u]^e[i].l);
dep[v]=dep[u]+log(e[i].l2)-log(e[i].l1);
DFS(v,u);
}
else {
if(d[v]!=(d[u]^e[i].l) || fabs(dep[u]-dep[v]+log(e[i].l2)-log(e[i].l1))>eps){flag=1;return;}
}
}
}
int main(){
freopen("4602.in","r",stdin);
freopen("4602.out","w",stdout);
scanf("%d",&t);
for(int i=1;i<=t;i++){
scanf("%d %d",&n,&m);
memset(vis,0,sizeof(vis));
memset(h,0,sizeof(h));
en=flag=0;
for(int j=1;j<=m;j++){
int u,v,x,y;
scanf("%d %d %d %d",&u,&v,&x,&y);
if(y<0){AddEdge(u,v,x,-y,1);AddEdge(v,u,-y,x,1);}
else {AddEdge(u,v,x,y,0);AddEdge(v,u,y,x,0);}
}
for(int j=1;j<=n && !flag;j++)if(!vis[j]){dep[j]=0;DFS(j,j);}
printf("Case #%d: %s\n",i,flag?"No":"Yes");
}
return 0;
}
Lucas定理的运用
$C(n,k)=C(n/Mod,k/Mod)*C(n\%Mod,k\%Mod)$
那么我们发现因为是求$C(n,0)+C(n,1)+...+C(n,k)$,对于其中的$C(n\%Mod,i)$,$0<=i<=k\%Mod$似乎会用很多次
然后推一下式子就发现这个可以处理成一个前缀和
然后就没了
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
const int Mod=2333;
int t,C[Mod][Mod],Sum[Mod][Mod];
long long n,k;
void Pre(){
C[0][0]=1;
for(int i=1;i<Mod;i++){
C[i][0]=C[i][i]=1;
for(int j=1;j<i;j++){C[i][j]=C[i-1][j]+C[i-1][j-1];if(C[i][j]>=Mod)C[i][j]-=Mod;}
}
for(int i=0;i<Mod;i++)Sum[0][i]=1;
for(int i=1;i<Mod;i++){
Sum[i][0]=1;
for(int j=1;j<Mod;j++){Sum[i][j]=Sum[i][j-1]+C[i][j];if(Sum[i][j]>=Mod)Sum[i][j]-=Mod;}
}
}
int Lucas(long long n,long long k){return k==0?1:C[n%Mod][k%Mod]*Lucas(n/Mod,k/Mod)%Mod;}
int Cal(long long n,long long k){
if(k<0)return 0;
if(n<Mod)return Sum[n][k];
return (Lucas(n/Mod,k/Mod)*Sum[n%Mod][k%Mod]+Cal(n/Mod,k/Mod-1)*Sum[n%Mod][Mod-1])%Mod;
}
int main(){
freopen("4591.in","r",stdin);
freopen("4591.out","w",stdout);
scanf("%d",&t);
Pre();
while(t--){
scanf("%lld %lld",&n,&k);
printf("%d\n",Cal(n,k));
}
return 0;
}
首先这题显然是线段树
0操作 区间直接赋值为0 很简单
2操作 统计最长连续0的个数 记录lx,rx,mx三个量,随便合并一下就行了,很简单
1操作……
首先需要记录一个sum表示当前区间有多少脑组织
然后二分填满的位置,我偷懒写了线段树外面的二分,然后时间复杂度就多了一个log
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=200005;
int n,m;
struct SegTree{
int lx,rx,mx,tag,sum,l,r;
}tree[N<<2];
void Pushdown(int rt){
if(tree[rt].tag==1){
tree[rt<<1].tag=1;
tree[rt<<1|1].tag=1;
tree[rt<<1].lx=tree[rt<<1].rx=tree[rt<<1].mx=0;
tree[rt<<1].sum=tree[rt<<1].r-tree[rt<<1].l+1;
tree[rt<<1|1].lx=tree[rt<<1|1].rx=tree[rt<<1|1].mx=0;
tree[rt<<1|1].sum=tree[rt<<1|1].r-tree[rt<<1|1].l+1;
tree[rt].tag=0;
}
if(tree[rt].tag==-1){
tree[rt<<1].tag=-1;
tree[rt<<1|1].tag=-1;
tree[rt<<1].lx=tree[rt<<1].rx=tree[rt<<1].mx=tree[rt<<1].r-tree[rt<<1].l+1;
tree[rt<<1].sum=0;
tree[rt<<1|1].lx=tree[rt<<1|1].rx=tree[rt<<1|1].mx=tree[rt<<1|1].rx=tree[rt<<1|1].mx=tree[rt<<1|1].r-tree[rt<<1|1].l+1;
tree[rt<<1|1].sum=0;
tree[rt].tag=0;
}
}
void Pushup(int rt){
tree[rt].mx=max(max(tree[rt<<1].mx,tree[rt<<1|1].mx),tree[rt<<1].rx+tree[rt<<1|1].lx);
tree[rt].lx=tree[rt<<1].lx;tree[rt].rx=tree[rt<<1|1].rx;
if(tree[rt<<1].lx==tree[rt<<1].r-tree[rt<<1].l+1)tree[rt].lx=tree[rt<<1].lx+tree[rt<<1|1].lx;
if(tree[rt<<1|1].rx==tree[rt<<1|1].r-tree[rt<<1|1].l+1)tree[rt].rx=tree[rt<<1|1].rx+tree[rt<<1].rx;
tree[rt].sum=tree[rt<<1].sum+tree[rt<<1|1].sum;
}
void Build(int rt,int l,int r){
tree[rt].l=l;tree[rt].r=r;
if(l==r){tree[rt].mx=tree[rt].lx=tree[rt].rx=0;tree[rt].sum=1;return;}
int mid=l+r>>1;
Build(rt<<1,l,mid);
Build(rt<<1|1,mid+1,r);
Pushup(rt);
}
void Update(int rt,int l,int r,int val){
if(l<=tree[rt].l && tree[rt].r<=r){
tree[rt].tag=val;
if(val==-1){tree[rt].lx=tree[rt].rx=tree[rt].mx=tree[rt].r-tree[rt].l+1;tree[rt].sum=0;}
if(val==1){tree[rt].lx=tree[rt].rx=tree[rt].mx=0;tree[rt].sum=tree[rt].r-tree[rt].l+1;}
return;
}
Pushdown(rt);
int mid=tree[rt].l+tree[rt].r>>1;
if(l<=mid)Update(rt<<1,l,r,val);
if(r>mid)Update(rt<<1|1,l,r,val);
Pushup(rt);
}
int GetSum(int rt,int l,int r){
if(l<=tree[rt].l & tree[rt].r<=r)return tree[rt].sum;
Pushdown(rt);
int mid=tree[rt].l+tree[rt].r>>1;
if(l>mid)return GetSum(rt<<1|1,l,r);
else if(r<=mid)return GetSum(rt<<1,l,r);
else return GetSum(rt<<1,l,r)+GetSum(rt<<1|1,l,r);
Pushup(rt);
}
void Solve(int l0,int r0,int l1,int r1){
int ResL=GetSum(1,l0,r0);
Update(1,l0,r0,-1);
int ResR=GetSum(1,l1,r1);
//printf("Res:%d %d\n",ResL,ResR);
if(ResL+ResR>=r1-l1+1){Update(1,l1,r1,1);/*puts("666!");*/}
else {
int l=l1,r=r1;
while(l<=r){
int mid=l+r>>1,t=GetSum(1,l1,mid);
if(mid-l1+1-t==ResL){Update(1,l1,mid,1);return;}
else if(mid-l1+1<ResL+t)l=mid+1;
else if(mid-l1+1>ResL+t)r=mid-1;
}
}
}
SegTree Merge(SegTree L,SegTree R){
SegTree M;
M.mx=max(max(L.mx,R.mx),L.rx+R.lx);
M.lx=L.lx;M.rx=R.rx;
if(L.sum==0)M.lx=L.lx+R.lx;
if(R.sum==0)M.rx=L.rx+R.rx;
M.sum=max(L.sum,R.sum);
return M;
}
SegTree GetMax(int rt,int l,int r){
if(l<=tree[rt].l && tree[rt].r<=r)return tree[rt];
Pushdown(rt);
int mid=tree[rt].l+tree[rt].r>>1;
if(l>mid)return GetMax(rt<<1|1,l,r);
else if(r<=mid)return GetMax(rt<<1,l,r);
else {return Merge(GetMax(rt<<1,l,r),GetMax(rt<<1|1,l,r));}
Pushup(rt);
}
void Print(){
//puts("233:");
for(int i=1;i<=n;i++)printf("%d ",GetSum(1,i,i));
putchar('\n');
}
int main(){
freopen("4592.in","r",stdin);
freopen("4592.out","w",stdout);
scanf("%d %d",&n,&m);
Build(1,1,n);
//Print();
for(int i=1;i<=m;i++){
int opt,l0,r0,l1,r1;
scanf("%d %d %d",&opt,&l0,&r0);
if(opt==1)scanf("%d %d",&l1,&r1);
if(opt==0)Update(1,l0,r0,-1);
if(opt==1)Solve(l0,r0,l1,r1);
if(opt==2)printf("%d\n",GetMax(1,l0,r0).mx);
//Print();
}
return 0;
}
考虑点分治
一棵一棵子树处理
用set判断一下有没有与len相等的值就可以了
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<set>
#include<algorithm>
using namespace std;
const int N=10005,INF=2100000000;
int n,p,len[N],h[N],en,siz[N],vis[N],mx[N],val,root,ans[N],cnt;
long long dis[N*105];
set<long long> St;
struct Edge{
int b,next;
long long v;
}e[2*N];
void AddEdge(int sa,int sb,long long sc){
e[++en].b=sb;
e[en].v=sc;
e[en].next=h[sa];
h[sa]=en;
}
void DfsSiz(int u,int fa){
siz[u]=1;mx[u]=0;
for(int i=h[u];i;i=e[i].next){
int v=e[i].b;
if(fa!=v && !vis[v]){
DfsSiz(v,u);
siz[u]+=siz[v];
mx[u]=max(mx[u],siz[v]);
}
}
}
void DfsRoot(int point,int u,int fa){
mx[u]=max(mx[u],siz[point]-mx[u]);
if(val>mx[u]){val=mx[u];root=u;}
for(int i=h[u];i;i=e[i].next){
int v=e[i].b;
if(v!=fa && !vis[v])DfsRoot(point,v,u);
}
}
void Cal(int u,int fa,long long val){
for(int i=1;i<=p;i++)if(St.find(len[i]-val)!=St.end())ans[i]=1;
dis[++cnt]=val;
for(int i=h[u];i;i=e[i].next){
int v=e[i].b;
if(v!=fa & !vis[v])Cal(v,u,val+e[i].v);
}
}
void DFS(int u){
val=INF;
DfsSiz(u,u);
DfsRoot(u,u,0);
St.clear();
St.insert(0);
//printf("Root:%d\n",root);
vis[root]=1;
for(int i=h[root];i;i=e[i].next){
int v=e[i].b;
if(!vis[v]){
cnt=0;
//printf("%d %d\n",cnt,v);
Cal(v,v,e[i].v);
for(int j=1;j<=cnt;j++){St.insert(dis[j]);/*printf("%d\n",dis[j]);*/}
}
}
for(int i=h[root];i;i=e[i].next){
int v=e[i].b;
if(!vis[v])DFS(v);
}
}
int main(){
freopen("1316.in","r",stdin);
freopen("1316.out","w",stdout);
scanf("%d %d",&n,&p);
for(int i=1;i<n;i++){
int u,v,w;
scanf("%d %d %d",&u,&v,&w);
AddEdge(u,v,w);
AddEdge(v,u,w);
}
for(int i=1;i<=p;i++)scanf("%d",&len[i]);
DFS(1);
for(int i=1;i<=p;i++)puts(ans[i]||!len[i]?"Yes":"No");
return 0;
}
Host by is-Programmer.com | Power by Chito 1.3.3 beta | Theme: Aeros 2.0 by TheBuckmaker.com