zoukankan      html  css  js  c++  java
  • LOJ#6038. 「雅礼集训 2017 Day5」远行(LCT)

    题面

    传送门

    题解

    要不是因为数组版的(LCT)跑得实在太慢我至于去学指针版的么……而且指针版的完全看不懂啊……

    首先有两个结论

    1.与一个点距离最大的点为任意一条直径的两个端点之一

    2.两棵树之间连一条边新树直径的端点一定是第一棵树直径的两个端点和第二颗树直径的两个端点这四个点之二

    然后用并查集维护联通块的直径就行了。注意因为这里强制在线,所以得用(LCT)来维护距离

    并不建议看代码因为这个代码非常难懂哪怕我加满注释您都不一定看得懂

    //minamoto
    #include<bits/stdc++.h>
    #define R register
    #define inline __inline__ __attribute__((always_inline))
    #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;
    }
    inline int getop(){R char ch;while((ch=getc())>'9'||ch<'0');return ch-'0';}
    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=3e5+5;
    struct node;typedef node* ptr;
    inline void swap(R ptr &x,R ptr &y){R ptr t=x;x=y,y=t;}
    inline int max(R int &x,R int &y){return x>y?x:y;}
    struct node{
    	ptr fa,lc,rc;int s;bool r;
    	inline node();
    	inline void ppd(){swap(lc,rc),r^=1;}
    	inline void pd(){if(r)lc->ppd(),rc->ppd(),r=0;}
    	inline ptr upd(){return s=lc->s+rc->s+1,this;}
    }e[N];
    inline node::node(){fa=lc=rc=e;}
    inline bool isrt(R ptr p){return p->fa->lc!=p&&p->fa->rc!=p;}
    void rotate(ptr p){
    	ptr s=p->fa,t=s->fa;
    	if(!isrt(s))(t->lc==s?t->lc:t->rc)=p;
    	p->fa=t,s->fa=p;
    	if(s->lc==p)s->lc=p->rc,p->rc->fa=s,p->rc=s->upd();
    		else s->rc=p->lc,p->lc->fa=s,p->lc=s->upd();
    }
    void push(ptr p){if(!isrt(p))push(p->fa);p->pd();}
    ptr splay(ptr p){
    	push(p);
    	while(!isrt(p)){
    		if(!isrt(p->fa))rotate(p==p->fa->lc^p->fa==p->fa->fa->lc?p:p->fa);
    		rotate(p);
    	}
    	return p->upd();
    }
    ptr exp(ptr p){
    	ptr s=e;
    	while(p!=e)splay(p)->rc=s,s=p->upd(),p=p->fa;
    	return s;
    }
    ptr exp(R int i){return exp(e+i);}
    struct qwq{
    	int s,t,d;
    	inline qwq(){}
    	inline qwq(R int ss,R int tt,R int dd):s(ss),t(tt),d(dd){}
    }p[N];
    int ga[N];
    int find(int x){return ga[x]==x?x:ga[x]=find(ga[x]);}
    void link(int i,int j){
    	exp(i)->ppd(),exp(j)->ppd();
    	//上面两步已经完成了makeroot操作了 
    	//虽然还没有把i和j给splay上去 
    	int u=find(i),v=find(j);
    	int s1=exp(p[u].s)->s,s2=exp(p[u].t)->s;
    	//分别计算直径的两个端点到根节点的距离
    	//注意这里的距离 是指它们之间的点数,也包括根节点 
    	int s3=exp(p[v].s)->s,s4=exp(p[v].t)->s;
    	qwq a=p[u];
    	if(s1+s3-1>a.d)a=qwq(p[u].s,p[v].s,s1+s3-1);
    	if(s1+s4-1>a.d)a=qwq(p[u].s,p[v].t,s1+s4-1);
    	if(s2+s3-1>a.d)a=qwq(p[u].t,p[v].s,s2+s3-1);
    	if(s2+s4-1>a.d)a=qwq(p[u].t,p[v].t,s2+s4-1);
    	if(a.d>p[v].d)p[v]=a;
    	ga[u]=v,splay(e+i)->fa=e+j;
    }
    int ask(int i){
    	exp(i)->ppd();
    	int u=find(i),s1=exp(p[u].s)->s,s2=exp(p[u].t)->s;
    	return max(s1,s2)-1;
    }
    int n,ty,q,ans,op,u,v;
    int main(){
    //	freopen("testdata.in","r",stdin);
    	ty=read(),n=read(),q=read();
    	fp(i,1,n)ga[i]=i,p[i]=qwq(i,i,0);
    	while(q--){
    		op=read(),u=read()^(ans*ty);
    		if(op==1)v=read()^(ans*ty),link(u,v);
    		else print(ans=ask(u));
    	}
    	return Ot(),0;
    }
    
  • 相关阅读:
    sql server 数据查询基础
    sqlserver 用SQL语句操作数据
    sql server 用表组织数据
    sql server 程序的集散地 数据库
    JAVA 面向对象 File I/O
    JAVA 面向对象 多线程
    JAVA 面向对象 集合框架
    JAVA 面向对象 异常
    js内置对象、定时函数、document对象
    DOM
  • 原文地址:https://www.cnblogs.com/bztMinamoto/p/10713567.html
Copyright © 2011-2022 走看看