zoukankan      html  css  js  c++  java
  • CF1479D Odd Mineral Resource

    CF1479D Odd Mineral Resource

    树分块+莫队。

    直接套上树分块莫队之后,统计答案使用值域分块。

    首先,我们对值域分块,每一个块开一个栈,表示这个值域里当前可能是答案的数

    什么叫做"可能成为答案的数"呢?相当于就是更新后当前是奇数次的数,只要这个数是奇数次了,我们就把它放进候选集合(栈)里,不管它之后会不会变成偶数。

    然后我们对于一个询问区间,边角直接暴力判断其 (cnt) 满不满足即可,然后遍历每一个大块,取出候选集合依次暴力判断。

    我们发现这样做的时间复杂度是 (O(nsqrt{n})) 的,因为我们莫队只会拓展 (nsqrt{n}) 个状态

    代码:

    #include <bits/stdc++.h>
    using namespace std;
    template <typename T>
    inline void read(T &x){
    	x=0;char ch=getchar();bool f=false;
    	while(!isdigit(ch)){if(ch=='-'){f=true;}ch=getchar();}
    	while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
    	x=f?-x:x;
    	return ;
    }
    template <typename T>
    inline void write(T x){
    	if(x<0) putchar('-'),x=-x;
    	if(x>9) write(x/10);
    	putchar(x%10^48);
    	return ;
    }
    #define ll long long
    const int N=3e5+5,INF=1e9+7;
    struct Query{
        int u,v,id,l,r;
        Query(int u=0,int v=0,int id=0,int l=0,int r=0):u(u),v(v),id(id),l(l),r(r){}
    }Q[N];
    int val[N],w[N],fa[N],dep[N],son[N],sta[N];
    int siz[N],top[N],bl[N],a[N],sum[N],b[N],dfn[N],DFN;
    bool vis[N];
    int n,m,q,Top,idx,cnt1,Cnt,block;
    int res,Ans[N];
    vector<int> vec[N];
    void dfs1(int u,int f){
    	int now=Top;
    	sta[++Top]=u,fa[u]=f,dep[u]=dep[f]+1,siz[u]=1,dfn[u]=++DFN;//压入栈和更新信息 
    	for(auto v:vec[u]){
    		if(v==f) continue;
    		dfs1(v,u);
    		if(Top-now>block){//如果里面的点多于 B 个 
    			idx++;//块编号 
    			while(Top!=now) bl[sta[Top--]]=idx;//更新节点所属块 
    		}
    		siz[u]+=siz[v];
    		if(siz[v]>siz[son[u]]) son[u]=v; 
    	}
    	return ;
    }
    void dfs2(int u,int f){//树剖预处理 
    	top[u]=f;
    	if(!son[u]) return ;
    	dfs2(son[u],f);
    	for(auto v:vec[u]){
    		if(v==fa[u]||v==son[u]) continue;
    		dfs2(v,v);
    	}
    	return ;
    }
    inline int QueryLca(int u,int v){//查询lca 
    	while(top[u]!=top[v]){
    		if(dep[top[u]]<dep[top[v]]) swap(u,v);
    		u=fa[top[u]];
    	}
    	if(dep[u]<dep[v]) return u;
    	return v;
    }
    inline bool cmp(Query a,Query b){//莫队排序 
    	return bl[a.u]!=bl[b.u]?bl[a.u]<bl[b.u]:bl[a.u]&1?dfn[a.v]<dfn[b.v]:dfn[a.v]>dfn[b.v];
    }
    stack<int> S[N];
    inline void Update(int u){//把u这个点取反的影响(用变不用,不用变用) 
    	if(vis[u]){
    		sum[a[u]]--;
    		if(sum[a[u]]&1) S[(a[u]-1)/block+1].push(a[u]);  
    		vis[u]=false;
    	}
    	else{
    		sum[a[u]]++;
    		if(sum[a[u]]&1) S[(a[u]-1)/block+1].push(a[u]);  
    		vis[u]=true;
    	}
    	return ;
    }
    inline void Move(int u,int v){//把u->v这条路径的更新了 
    	if(dep[u]<dep[v]) swap(u,v);
    	while(dep[u]>dep[v]) Update(u),u=fa[u];
    	while(u!=v) Update(u),Update(v),u=fa[u],v=fa[v];
    	return ;
    }
    int main(){
    	read(n),read(m);
    	block=sqrt(n);
    	int Ncnt=0;
    	for(int i=1;i<=n;i++) read(a[i]);//a是最初的颜色 
    	for(int i=1;i<n;i++){//建图 
    		int u,v;read(u),read(v);
    		vec[u].push_back(v),vec[v].push_back(u);
    	}
    	for(int i=1;i<=m;i++){
    		int op,u,v,a,b;
    		read(u),read(v),read(a),read(b);
    		if(dfn[u]>dfn[v]) swap(u,v);
    		++Cnt,Q[Cnt]=Query(u,v,Cnt,a,b);//l,r,id
    	}
    	dfs1(1,0),dfs2(1,1);//分块和LCA预处理 
    	while(Top>0) bl[sta[Top--]]=idx;//分完块 
    	sort(Q+1,Q+Cnt+1,cmp);//莫队排序 
    	int u,v,t;
    	u=v=1,t=0;
    	Update(1);//初始化第一个点 
    	for(int i=1;i<=Cnt;i++){//处理询问 
    		Update(QueryLca(u,v));//两个LCA在这里要单独讨论 
    		if(u!=Q[i].u) Move(u,Q[i].u),u=Q[i].u;//u更新到u` 
    		if(v!=Q[i].v) Move(v,Q[i].v),v=Q[i].v;//v更新到v` 
    		Update(QueryLca(u,v));//讨论 
    		int p=(Q[i].l-1)/block+1,q=(Q[i].r-1)/block+1,ans=-1;
    		if(p==q){
    			for(int k=Q[i].l;k<=Q[i].r;k++) if(sum[k]&1) ans=k;
    		}
    		else{
    			for(int k=Q[i].l;k<=p*block;k++) if(sum[k]&1) ans=k;
    			if(ans!=-1){Ans[Q[i].id]=ans;continue;}
    			for(int k=(q-1)*block+1;k<=Q[i].r;k++) if(sum[k]&1) ans=k;
    			if(ans!=-1){Ans[Q[i].id]=ans;continue;}
    			for(int k=p+1;k<=q-1;k++){
    				if(ans!=-1) break;
    				while(!S[k].empty()){
    					int x=S[k].top();
    					if(sum[x]&1) ans=x;
    					if(ans!=-1) break;
    					S[k].pop();
    				}
    			}
    		}
    		Ans[Q[i].id]=ans;
    	}
    	for(int i=1;i<=Cnt;i++) write(Ans[i]),putchar('
    '); 
    	return 0; 
    }
    
  • 相关阅读:
    golang获取URL
    Golang读取HTML中Table数据到二维数组
    Golang的GUI开发包fyne基本教程
    C#搭建安川机器人上位机
    程序计数器
    SpringBoot定时任务详解
    mysql 5.7安装
    springboot 配置多数据源
    mysql 查询某一天数据
    java如何获取当前日期和时间
  • 原文地址:https://www.cnblogs.com/Akmaey/p/14695998.html
Copyright © 2011-2022 走看看