zoukankan      html  css  js  c++  java
  • 机房测试9.22

    题解之前

    中秋只有一天假!

    build


    以为并查集水题,发现有历史版本,于是可持久化并查集一波(爆0了)

    其实有简单点的做法:用二元组记录每一次变化的siz和fa,二分查询即可。

    我还在肝可持久并查集,所以就没有代码了。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<vector>
    using namespace std;
    
    const int MAXN=100005 ;
    int n, m, fa[MAXN], times[MAXN], h[MAXN], nowT, size[MAXN];
    
    struct Info{
    	int tm, size ;
    	Info(int _tm=0,int _size=0){ tm=_tm , size=_size; }
    };
    
    vector<Info> vec[MAXN] ;
    vector<Info>::iterator it ;
    
    bool cmp(const Info &a, const Info &b){
    	return a.tm < b.tm ;
    }
    
    int findFa(int a){
    	if(fa[a]==a) return a;
    	return findFa(fa[a]) ;
    }
    
    void mergeNodes(int u,int v){
    	int fu=findFa(u), fv=findFa(v) ;
    	if(fu==fv) return ;
    	if(h[fu]<h[fv]) swap(fu,fv) ;
    	fa[fv]=fu, size[fu]+=size[fv], times[fv]=nowT ;
    	if(h[fu]==h[fv]) h[fu]++ ;
    	vec[fu].push_back(Info(nowT,size[fu])) ;
    }
    
    int query(int t, int a){
    	while(a!=fa[a] && times[a]<=t) a=fa[a] ;
    	it=upper_bound(vec[a].begin(),vec[a].end(),Info(t,0),cmp) ;
    	--it ;
    	return it->size ;
    }
    
    int main(){
    	freopen("build.in","r",stdin) ;
    	freopen("build.out","w",stdout) ;
    	scanf("%d%d",&n,&m) ;
    	for(int i=1;i<=n;++i) fa[i]=i, vec[i].push_back(Info(0,1)), h[i]=1, size[i]=1 ;
    	int lastans=0 ;
    	for(int i=1;i<=m;++i){
    		int t, u, v ;
    		nowT=i ;
    		scanf("%d%d%d",&t,&u,&v) ;
    		u+=lastans , v+=lastans ;
    		if(t==1){
    			mergeNodes(u,v) ;
    		}
    		else if(t==2){
    			printf("%d
    ",lastans=query(u,v)) ;
    		}
    	}
    	return 0 ;
    }
    

    清华爷的代码就是不一样。

    补:

    做出来了。

    其实二维线段树?

    #include<bits/stdc++.h>
    #define FN "build"
    
    const int maxn=1e5+5;
    
    inline int read() {
    	int x;char ch;bool flag=false;while(!isdigit(ch=getchar()))
    	(ch=='-') && (flag=true);
    	for(x=ch-'0';isdigit(ch=getchar());x=(x<<3)+(x<<1)+ch-'0');
    	return (flag?-x:x);
    }
    
    namespace HJT {
    	
    	int n;
    	
    	struct Node {
    		Node *ls,*rs;
    		int siz,fa;
    	}pool[maxn*32], *root[maxn], *zero, *tail=pool;
    	
    	Node *newnode() {
    		Node *nd=++tail;
    		nd->ls=nd->rs=zero;
    		nd->siz=nd->fa=0;
    		return nd;
    	}
    	
    	Node *Fmodify(Node *p,int l,int r,int pos,int rt) {
    		Node *nd=newnode();
    		if(l==r) {
    			nd->fa=rt;
    			nd->siz=p->siz;
    			return nd;
    		}
    		int mid=l+r>>1;
    		if(pos<=mid) {
    			nd->rs=p->rs;
    			nd->ls=Fmodify(p->ls,l,mid,pos,rt);
    		}
    		else {
    			nd->ls=p->ls;
    			nd->rs=Fmodify(p->rs,mid+1,r,pos,rt);
    		}
    		return nd;
    	}
    	
    	Node *Smodify(Node *p,int l,int r,int pos,int rt) {
    		Node *nd=newnode();
    		if(l==r) {
    			nd->fa=p->fa;
    			nd->siz=p->siz+rt;
    			return nd;
    		}
    		int mid=l+r>>1;
    		if(pos<=mid) {
    			nd->rs=p->rs;
    			nd->ls=Smodify(p->ls,l,mid,pos,rt);
    		}
    		else {
    			nd->ls=p->ls;
    			nd->rs=Smodify(p->rs,mid+1,r,pos,rt);
    		}
    		return nd;
    	}
    	
    	int Fquery(Node *nd,int l,int r,int pos) {
    		if(l==r) return nd->fa;
    		int mid=l+r>>1;
    		if(pos<=mid) return Fquery(nd->ls,l,mid,pos);
    		else return Fquery(nd->rs,mid+1,r,pos);
    	}
    	
    	int Squery(Node *nd,int l,int r,int pos) {
    		if(l==r) return nd->siz;
    		int mid=l+r>>1;
    		if(pos<=mid) return Squery(nd->ls,l,mid,pos);
    		else return Squery(nd->rs,mid+1,r,pos);
    	}
    	
    	int find(int i,Node *nd,int x) {
    		int ff=Fquery(nd,1,n,x);
    		if(ff==x) return x;
    		return find(i,nd,ff);
    	}
    	
    	Node *build(int l,int r) {
    		Node *nd=newnode();
    		if(l==r) {
    			nd->siz=1;
    			nd->fa=l;
    			return nd;
    		}
    		int mid=l+r>>1;
    		nd->ls=build(l,mid);
    		nd->rs=build(mid+1,r);
    		return nd;
    	}
    		
    	void work() {
    		int m=read();n=read();
    		int lastans=0,tot=0;
    		zero=++tail;
    		zero->ls=zero->rs=zero;
    		zero->fa=zero->siz=0;
    		root[0]=build(1,n);
    		for(int i=1;i<=m;i++) {
    			int opt=read();
    			int u=lastans+read();
    			int v=lastans+read();
    			if(opt==1) {
    				u=find(tot,root[tot],u);
    				v=find(tot,root[tot],v);
    				if(u==v) {
    					++tot;
    					root[tot]=root[tot-1];
    					continue;
    				}
    				int siz1=Squery(root[tot],1,n,v);
    				int siz2=Squery(root[tot],1,n,u);
    				if(siz1>siz2) {
    					std::swap(siz1,siz2);
    					std::swap(u,v);
    				}
    				++tot;
    				root[tot]=Fmodify(root[tot-1],1,n,v,u);
    				root[tot]=Smodify(root[tot],1,n,u,siz1);
    			}
    			else {
    				int ff=find(u,root[u],v);
    				int siz1=Squery(root[u],1,n,ff);
    				root[tot+1]=root[tot];
    				++tot;
    				lastans=siz1;
    				printf("%d
    ",siz1);
    			}
    		}
    	}
    }
    
    int main(){
    	freopen(FN".in","r",stdin);
    	freopen(FN".out","w",stdout);
    	HJT::work();
    	return 0;
    }
    

    妙啊。

    distribute

    我真的不认识这个单词。

    但是这道题水的惊人。

    dp[i] 表示先手在第 i 个物品时的最大收益。

    因为此题有后效性,选择从后往前for。

    如果上一手换了,就是sum[i+1]-dp[i+1]+a[i](sum为前缀和);

    如果没有换,就是dp[i+1]。

    取max即可。

    ye!

    其实可以从dp[i][0/1][0/1]慢慢来,总之只要知道必须从后往前,基本就对了。

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #define FN "distribute"
    
    const int maxn=1e5+5;
    
    int a[maxn];
    long long dp,sum;
    
    int main() {
    	freopen(FN".in","r",stdin);
    	freopen(FN".out","w",stdout);
    	int n;scanf("%d",&n);
    	for(int i=1;i<=n;i++) scanf("%d",a+i);
    	dp=sum=a[n];
    	for(int i=n-1;i>0;i--) {
    		sum+=a[i];
    		dp=std::max(dp,sum-dp);
    	}
    	printf("%lld",dp);
    	return 0;
    }
    

    find



    讲得好!

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    
    const int MAXN=100005 , MAXM=MAXN<<1 ;
    int n , m , first[MAXN] , nexts[MAXM] , to[MAXM] , egnum=1 ;
    int TTT, low[MAXN], dfn[MAXN], top, kNum, tag[MAXN], q[MAXM] , qnum , stk[MAXM] ;
    bool isAns[MAXM], vis[MAXM] ;
    
    void addEdge(int a,int b){
    	nexts[++egnum]=first[a] , first[a]=egnum , to[egnum]=b ;
    }
    
    void tarjan(int a,int fEdge){
    	dfn[a]=low[a]=++TTT ;
    	for(int i=first[a];i;i=nexts[i]){
    		int b=to[i] ;
    		if((i^1)==fEdge) continue ;
    		if(!vis[i]) vis[i]=vis[i^1]=true , stk[++top]=i ;
    		if(!dfn[b]){
    			tarjan(b,i) ;
    			low[a]=min(low[a],low[b]) ;
    			if(low[b]>=dfn[a]){
    				++kNum , qnum=0 ;
    				int cnt=0, t;
    				do{
    					t=stk[top--] ;
    					if(tag[to[t]]!=kNum) tag[to[t]]=kNum , ++cnt ;
    					if(tag[to[t^1]]!=kNum) tag[to[t^1]]=kNum , ++cnt ;
    					q[++qnum]=t ;
    				}while(t!=i);
    				if(qnum==cnt){
    					for(int i=1;i<=qnum;++i){
    						isAns[q[i]]=isAns[q[i]^1]=true ;
    					}
    				}
    			}
    		}
    		else if(dfn[b]<low[a]){
    			low[a]=min(low[a],dfn[b]) ;
    		}
    	}
    }
    
    int main(){
    	freopen("find.in","r",stdin) ;
    	freopen("find.out","w",stdout) ;
    	scanf("%d%d",&n,&m) ;
    	for(int i=1;i<=m;++i){
    		int a,b;
    		scanf("%d%d",&a,&b) ;
    		addEdge(a,b) , addEdge(b,a) ;
    	}
    	for(int i=1;i<=n;++i){
    		if(!dfn[i]){
    			tarjan(i,0) ;
    		}
    	}
    	int cnt=0 ;
    	for(int i=2;i<=egnum;i+=2) if(isAns[i]) ++cnt ;
    	printf("%d
    ",cnt);
    	for(int i=2;i<=egnum;i+=2) if(isAns[i])
    		printf("%d ",i/2) ;
    	printf("
    ") ;
    	return 0 ;
    }
    

    end

  • 相关阅读:
    关于PHP程序员技术职业生涯规划
    让PHP7达到最高性能的几个Tips
    php-fpm解读-进程管理的三种模式 及 worker进程、master进程详解
    CGI、FastCGI和php-fpm概念和区别
    什么是PHP7中的孤儿进程与僵尸进程,加上守护进程
    PHP 信号管理知识整理汇总
    PHP多进程---fork多个子进程,父进程阻塞与非阻塞
    锁存器、触发器和寄存器
    FPGA基础之锁存器与触发器的设计
    从CMOS到触发器(二)
  • 原文地址:https://www.cnblogs.com/LoLiK/p/9690309.html
Copyright © 2011-2022 走看看