zoukankan      html  css  js  c++  java
  • [UOJ198][CTSC2016]时空旅行

    uoj

    description

    你要维护若干个集合,每个集合都是有一个编号比他小的集合扩展而来,扩展内容为加入一个新的元素((x,c))或者删除一个已有元素。集合的扩展关系之间构成一个树形结构。
    (m)次询问,每次给出一个(x_0),询问第(s)个集合中((x-x_0)^2+c)的最小值。
    (n,mle5 imes10^5)

    sol

    把这个树形结构建出来,然后一个元素在树上存在的位置就是——一个连通块?
    这样转化显得很蠢,实际上一个元素在树上存在的位置就是它第一次出现的点的子树中扣掉把它删除的点的子树。
    这样子(n)种元素在树上的存在位置就是(n)个在(mbox{dfs})序上的连续区间。
    观察答案式,因为长得很斜率优化,所以就把这(n)个区间丢到线段树上,在线段树的每个节点维护一个下凸壳。每个询问就在线段树的一条链上的每个线段树节点里边的凸壳上二分。复杂度(O(nlog^2n))
    发现每次二分很蠢,可以直接在外部对询问的(x)排序,然后就不需要二分了。复杂度(O(nlog n))

    code

    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<vector>
    using namespace std;
    #define ll long long
    ll gi(){
    	ll x=0,w=1;char ch=getchar();
    	while ((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
    	if (ch=='-') w=0,ch=getchar();
    	while (ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
    	return w?x:-x;
    }
    const int N = 5e5+5;
    struct point{ll x,y;}p[N];
    struct node{
    	int x,s,id;
    	bool operator < (const node &b) const
    		{return x<b.x;}
    }q[N];
    vector<int>S[N];vector<int>v[N<<2];
    int n,m,nxt[N],head[N],val[N],dfn[N],low[N],tim,id[N],hd[N<<2];
    ll X[N],C[N],ans[N];
    void dfs(int u){
    	dfn[u]=++tim;S[val[u]].push_back(u);
    	for (int v=head[u];v;v=nxt[v]) dfs(v);
    	low[u]=tim;
    }
    bool cmp(int i,int j){return X[i]==X[j]?C[i]>C[j]:X[i]<X[j];}
    void modify(int x,int l,int r,int ql,int qr,int i){
    	if (l>=ql&&r<=qr){
    		int sz=v[x].size();
    		while(sz>1&&(p[v[x][sz-1]].y-p[v[x][sz-2]].y)*(p[i].x-p[v[x][sz-1]].x)>=(p[i].y-p[v[x][sz-1]].y)*(p[v[x][sz-1]].x-p[v[x][sz-2]].x))--sz,v[x].pop_back();
    		v[x].push_back(i);return;
    	}
    	int mid=l+r>>1;
    	if (ql<=mid) modify(x<<1,l,mid,ql,qr,i);
    	if (qr>mid) modify(x<<1|1,mid+1,r,ql,qr,i);
    }
    ll query(int x,int l,int r,int s,int k){
    	ll res=1ll<<60;
    	if (int sz=v[x].size()){
    		while (hd[x]<sz-1&&p[v[x][hd[x]+1]].y-p[v[x][hd[x]]].y<1ll*k*(p[v[x][hd[x]+1]].x-p[v[x][hd[x]]].x)) ++hd[x];
    		res=p[v[x][hd[x]]].y-p[v[x][hd[x]]].x*k+1ll*k*k;
    	}
    	if (l==r) return res;int mid=l+r>>1;
    	if (s<=mid) return min(res,query(x<<1,l,mid,s,k));
    	else return min(res,query(x<<1|1,mid+1,r,s,k));
    }
    int main(){
    	n=gi();m=gi();C[1]=gi();val[1]=1;
    	for (int i=2;i<=n;++i)
    		if (!gi()){
    			int f=gi()+1,id=gi()+1;
    			X[id]=gi();gi(),gi();C[id]=gi();
    			nxt[i]=head[f];head[f]=i;val[i]=id;
    		}else{
    			int f=gi()+1,id=gi()+1;
    			nxt[i]=head[f];head[f]=i;val[i]=id;
    		}
    	dfs(1);
    	for (int i=1;i<=n;++i) id[i]=i;sort(id+1,id+n+1,cmp);
    	for (int i=1;i<=n;++i)
    		if (S[id[i]].size()){
    			p[i]=(point){2ll*X[id[i]],X[id[i]]*X[id[i]]+C[id[i]]};
    			int lst=dfn[S[id[i]][0]];
    			for (int j=1,sz=S[id[i]].size();j<sz;++j){
    				if (lst<dfn[S[id[i]][j]]) modify(1,1,n,lst,dfn[S[id[i]][j]]-1,i);
    				lst=low[S[id[i]][j]]+1;
    			}
    			if (lst<=low[S[id[i]][0]]) modify(1,1,n,lst,low[S[id[i]][0]],i);
    		}
    	for (int i=1,s,x;i<=m;++i) s=gi()+1,x=gi(),q[i]=(node){x,dfn[s],i};
    	sort(q+1,q+m+1);
    	for (int i=1;i<=m;++i) ans[q[i].id]=query(1,1,n,q[i].s,q[i].x);
    	for (int i=1;i<=m;++i) printf("%lld
    ",ans[i]);
    	return 0;
    }
    
  • 相关阅读:
    第7次实践作业 25组
    第6次实践作业 25组
    第5次实践作业
    第4次实践作业
    第3次实践作业
    第2次实践作业
    第1次实践作业
    软工实践个人总结
    2019 SDN大作业
    C语言Il作业01
  • 原文地址:https://www.cnblogs.com/zhoushuyu/p/9385906.html
Copyright © 2011-2022 走看看