XXX speed

124 篇文章 0 订阅
31 篇文章 0 订阅

题目描述
比特山是比特镇的飙车圣地。在比特山上一共有n 个广场,编号依次为1 到n,这些广场之间通过n-1 条双向车道直接或间接地连接在一起,形成了一棵树的结构。
因为每条车道的修建时间以及建筑材料都不尽相同,所以可以用两个数字li、 ri 量化地表示一条车道的承受区间,只有当汽车以不小于li 且不大于ri 的速度经过这条车道时,才不会对路面造成伤害。Byteasar 最近新买了一辆跑车,他想在比特山飙一次车。Byteasar 计划选择两个不同的点S、 T,然后在它们树上的最短路径上行驶,且不对上面任意一条车道造成伤害。
Byteasar 不喜欢改变速度,所以他会告诉你他的车速。为了挑选出最合适的车速,Byteasar 一共会向你询问m 次。请帮助他找到一条合法的道路,使得路径上经过的车道数尽可能多。
输入
第一行包含两个正整数n,m,表示广场的总数和询问的总数。
接下来n-1 行,每行四个正整数ui, vi, li, ri,表示一条连接ui 和vi 的双向车道,且承受区间为[li,ri]。接下来m 行,每行一个正整数qi,分别表示每个询问的车速。
输出
输出m 行,每行一个整数,其中第i 行输出车速为qi 时的最长路径的长度,如果找不到合法的路径则输出0。

线段树优化套直径合并。
对于有效区间为[L,R]的修改的题目,可以考虑把修改放到线段树上当做永久化标记,然后对线段树进行DFS,利用恢复操作,充分利用每一层的答案。 至于直径合并,自己想想就行。由于恢复操作,并查集要用按高度排序(比按大小排序居然快了300ms)

AC Code:

#include<cstdio>
#include<cstring>
#include<cctype>
#include<algorithm>
#include<vector>
#include<cmath>
#define maxn 70005
#define lim 18
#define lc now<<1
#define rc now<<1|1
using namespace std;

namespace IO{ 
    #define BUF_SIZE 100000 
    #define OUT_SIZE 100000 
    #define ll long long 
    //fread->read 
 
    bool IOerror=0; 
    inline char nc(){ 
        static char buf[BUF_SIZE],*p1=buf+BUF_SIZE,*pend=buf+BUF_SIZE; 
        if (p1==pend){ 
            p1=buf; pend=buf+fread(buf,1,BUF_SIZE,stdin); 
            if (pend==p1){IOerror=1;return -1;} 
            //{printf("IO error!\n");system("pause");for (;;);exit(0);} 
        } 
        return *p1++; 
    } 
    inline bool blank(char ch){return ch==' '||ch=='\n'||ch=='\r'||ch=='\t';} 
    inline void read(int &x){ 
        bool sign=0; char ch=nc(); x=0; 
        for (;blank(ch);ch=nc()); 
        if (IOerror)return; 
        if (ch=='-')sign=1,ch=nc(); 
        for (;ch>='0'&&ch<='9';ch=nc())x=x*10+ch-'0'; 
        if (sign)x=-x; 
    } 
    inline void read(ll &x){ 
        bool sign=0; char ch=nc(); x=0; 
        for (;blank(ch);ch=nc()); 
        if (IOerror)return; 
        if (ch=='-')sign=1,ch=nc(); 
        for (;ch>='0'&&ch<='9';ch=nc())x=x*10+ch-'0'; 
        if (sign)x=-x; 
    } 
    inline void read(double &x){ 
        bool sign=0; char ch=nc(); x=0; 
        for (;blank(ch);ch=nc()); 
        if (IOerror)return; 
        if (ch=='-')sign=1,ch=nc(); 
        for (;ch>='0'&&ch<='9';ch=nc())x=x*10+ch-'0'; 
        if (ch=='.'){ 
            double tmp=1; ch=nc(); 
            for (;ch>='0'&&ch<='9';ch=nc())tmp/=10.0,x+=tmp*(ch-'0'); 
        } 
        if (sign)x=-x; 
    } 
    inline void read(char *s){ 
        char ch=nc(); 
        for (;blank(ch);ch=nc()); 
        if (IOerror)return; 
        for (;!blank(ch)&&!IOerror;ch=nc())*s++=ch; 
        *s=0; 
    } 
    inline void read(char &c){ 
        for (c=nc();blank(c);c=nc()); 
        if (IOerror){c=-1;return;} 
    } 
    //fwrite->write 
    struct Ostream_fwrite{ 
        char *buf,*p1,*pend; 
        Ostream_fwrite(){buf=new char[BUF_SIZE];p1=buf;pend=buf+BUF_SIZE;} 
        void out(char ch){ 
            if (p1==pend){ 
                fwrite(buf,1,BUF_SIZE,stdout);p1=buf; 
            } 
            *p1++=ch; 
        } 
        void print(int x){ 
            static char s[15],*s1;s1=s; 
            if (!x)*s1++='0';if (x<0)out('-'),x=-x; 
            while(x)*s1++=x%10+'0',x/=10; 
            while(s1--!=s)out(*s1); 
        } 
        void println(int x){ 
            static char s[15],*s1;s1=s; 
            if (!x)*s1++='0';if (x<0)out('-'),x=-x; 
            while(x)*s1++=x%10+'0',x/=10; 
            while(s1--!=s)out(*s1); out('\n'); 
        } 
        void print(ll x){ 
            static char s[25],*s1;s1=s; 
            if (!x)*s1++='0';if (x<0)out('-'),x=-x; 
            while(x)*s1++=x%10+'0',x/=10; 
            while(s1--!=s)out(*s1); 
        } 
        void println(ll x){ 
            static char s[25],*s1;s1=s; 
            if (!x)*s1++='0';if (x<0)out('-'),x=-x; 
            while(x)*s1++=x%10+'0',x/=10; 
            while(s1--!=s)out(*s1); out('\n'); 
        } 
        void print(double x,int y){ 
            static ll mul[]={1,10,100,1000,10000,100000,1000000,10000000,100000000, 
                1000000000,10000000000LL,100000000000LL,1000000000000LL,10000000000000LL, 
                100000000000000LL,1000000000000000LL,10000000000000000LL,100000000000000000LL}; 
            if (x<-1e-12)out('-'),x=-x;x*=mul[y]; 
            ll x1=(ll)floor(x); if (x-floor(x)>=0.5)++x1; 
            ll x2=x1/mul[y],x3=x1-x2*mul[y]; print(x2); 
            if (y>0){out('.'); for (size_t i=1;i<y&&x3*mul[i]<mul[y];out('0'),++i); print(x3);} 
        } 
        void println(double x,int y){print(x,y);out('\n');} 
        void print(char *s){while (*s)out(*s++);} 
        void println(char *s){while (*s)out(*s++);out('\n');} 
        void flush(){if (p1!=buf){fwrite(buf,1,p1-buf,stdout);p1=buf;}} 
        ~Ostream_fwrite(){flush();} 
    }Ostream; 
    inline void print(int x){Ostream.print(x);} 
    inline void println(int x){Ostream.println(x);} 
    inline void print(char x){Ostream.out(x);} 
    inline void println(char x){Ostream.out(x);Ostream.out('\n');} 
    inline void print(ll x){Ostream.print(x);} 
    inline void println(ll x){Ostream.println(x);} 
    inline void print(double x,int y){Ostream.print(x,y);} 
    inline void println(double x,int y){Ostream.println(x,y);} 
    inline void print(char *s){Ostream.print(s);} 
    inline void println(char *s){Ostream.println(s);} 
    inline void println(){Ostream.out('\n');} 
    inline void flush(){Ostream.flush();}
    #undef ll 
    #undef OUT_SIZE 
    #undef BUF_SIZE 
};

using namespace IO;

int info[maxn],Prev[maxn<<1],to[maxn<<1],cnt_e;
inline void Node(const int &u,const int &v){ Prev[++cnt_e]=info[u],info[u]=cnt_e,to[cnt_e]=v; }

int n,m;
int x[maxn],y[maxn],rec[maxn][7];
vector<int>vec[maxn*10];
// remember to check how much MB I used;
// 23 MB perfect

void insert(int now,int l,int r,int ql,int qr,int id)
{
	if(ql > r || qr < l) return;
	if(ql <= l && r <= qr){vec[now].push_back(id);return;}
	int mid =(l+r)>>1;
	insert(lc,l,mid,ql,qr,id),insert(rc,mid+1,r,ql,qr,id);
}

int ans[maxn],siz[maxn],loc[2][maxn],dis[maxn];
int Min[lim][maxn<<1],tot,pos[maxn],dep[maxn],F[maxn],lg[maxn<<1];

inline int Find(int now){ 
	return !F[now] ? now : Find(F[now]); 
}

void dfs(int now,int ff)
{
	dep[now] = dep[ff] + 1;
	Min[0][pos[now] = ++tot] = now;
	for(int i=info[now];i;i=Prev[i])
		if(to[i]!=ff)
		{
			dfs(to[i],now);
			Min[0][++tot] = now;
		}
}

inline int Lca(int u,int v)
{
	u = pos[u] , v = pos[v];
	if(u > v) swap(u,v);
	int tmp = lg[v - u + 1];
	return dep[Min[tmp][u]] < dep[Min[tmp][v-(1<<tmp)+1]] ? Min[tmp][u] : Min[tmp][v-(1<<tmp)+1];
}

inline int Dis(int u,int v)
{
	int lca = Lca(u,v);
	return dep[u] + dep[v] - 2 * dep[lca];
}

int Maxlen = 0;

inline void add(int id)
{
	int u = Find(x[id]) , v = Find(y[id]);
	
	int a[2]={Dis(x[id],loc[0][u]),Dis(x[id],loc[1][u])},b[2]={Dis(y[id],loc[0][v]),Dis(y[id],loc[1][v])};
	int ndis=0,tmp=(a[a[1] > a[0]] + b[b[1] > b[0]] + 1),LC[2];
	if(dis[u] > dis[v])
	{
		if(dis[u] > tmp) ndis = dis[u] , LC[0] = loc[0][u] , LC[1] = loc[1][u];
		else ndis = tmp , LC[0] = loc[a[1] > a[0]][u] , LC[1] = loc[b[1] > b[0]][v];
	}
	else
	{
		if(dis[v] > tmp) ndis = dis[v] , LC[0] = loc[0][v] , LC[1] = loc[1][v];
		else ndis = tmp , LC[0] = loc[a[1] > a[0]][u] , LC[1] = loc[b[1] > b[0]][v];
	}
	
	if(siz[u] > siz[v]) swap(u,v);
	rec[id][0] = u , F[u] = v ;
	rec[id][5] = Maxlen;
	Maxlen = max(Maxlen,ndis);
	rec[id][1] = v , rec[id][2] = dis[v] , dis[v] = ndis;
	rec[id][3] = loc[0][v] , rec[id][4] = loc[1][v];
	loc[0][v] = LC[0] , loc[1][v] = LC[1];
	rec[id][6] = siz[v];
	siz[v] = (siz[u] == siz[v] ? siz[v]+1 : siz[v]);
}

inline void recover(int id)
{
	int u = rec[id][0] , v = rec[id][1];
	Maxlen = rec[id][5];
	F[u] = 0 , dis[v] = rec[id][2];
	loc[0][v] = rec[id][3] , loc[1][v] = rec[id][4];
	siz[v] = rec[id][6];
}

void solve(int now,int l,int r)
{
	if(l>r) return;
	for(int i=0,siz=vec[now].size();i<siz;i++)
		add(vec[now][i]);
	if(l == r){ 
		ans[l] = Maxlen;	
		for(int siz=vec[now].size(),i=siz-1;i>=0;i--) 
			recover(vec[now][i]);
		return;
	}
	int mid = (l + r) >> 1;
	solve(lc,l , mid);
	solve(rc,mid+1,r);
	for(int siz=vec[now].size(),i=siz-1;i>=0;i--) 
		recover(vec[now][i]);
}

int main()
{
	
	read(n),read(m);
	for(int i=1,l,r;i<n;i++)
	{
		read(x[i]),read(y[i]),read(l),read(r);
		Node(x[i],y[i]),Node(y[i],x[i]);
		insert(1,1,n,l,r,i);
	}
	
	for(int i=1;i<=n;i++) loc[0][i] = loc[1][i] = i , siz[i] = 1;
	
	dfs(1,0);
	for(int i=1,LG=-1,sum=1;i<=tot;lg[i] = LG,i++) if(sum == i) LG++ , sum <<=1;
	for(int j=1;j<lim;j++)
		for(register int i=1;i<=tot;i++)
			if(i + (1<<j-1) <= tot)
				Min[j][i] = dep[Min[j-1][i]] < dep[Min[j-1][i + (1<<j-1)]] ? Min[j-1][i] : Min[j-1][i+(1<<j-1)];
	
	solve(1,1,n);
	
	for(int tmp;m--;)
		read(tmp),println(ans[tmp]);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值