zoukankan      html  css  js  c++  java
  • P4155 [SCOI2015]国旗计划

    很有意思的一道题。

    按套路破环成链,要注意右端点小于左端点的区间跨越了 (n o 1)

    假设钦定了某个士兵 (i),接下来肯定贪心选择左端点小于等于当前右端点的右端点最大的下一个区间。因为区间不存在包含关系,所以形式化地讲就是找到最大的 (j) 使得 (C_jleq D_i)

    直接做是 (O(N^2)) 的,但观察到一条决策链中点的决策是存在重合的,即 (j) 的决策可以部分应用到 (i) 上面,并且存在单调性(因为不存在包含关系)。

    考虑 (i)(j) 之间连边,这样会形成一个决策森林。其中点 (u) 的答案为距离 (u) 最近的祖先 (v) 使得 (D_vgeq C_u+m)

    从根节点开始双指针,但上端点移动时需要朝着下端点的方向。这个只需要更新边表头就行了,即进入过的儿子直接跳过。

    除排序外时间复杂度 (O(N))

    code:

    #include<bits/stdc++.h>
    using namespace std;
    #define N 400005
    #define For(i,x,y)for(i=x;i<=(y);i++)
    #define Down(i,x,y)for(i=x;i>=(y);i--)
    #define int long long
    struct node
    {
    	int next,to;
    }e[N];
    struct soldier
    {
    	int c,d,id;
    }a[N];
    bool used[N];
    int head[N],dep[N],res[200005],g,m;
    inline void add(int u)
    {
    	e[++g].next=head[u];
    	head[u]=g;
    }
    int read()
    {
    	int A;
    	bool K;
    	char C;
    	C=A=K=0;
    	while(C<'0'||C>'9')K|=C=='-',C=getchar();
    	while(C>'/'&&C<':')A=(A<<3)+(A<<1)+(C^48),C=getchar();
    	return(K?-A:A);
    }
    void write(int X)
    {
    	if(X<0)putchar('-'),X=-X;
    	if(X>9)write(X/10);
    	putchar(X%10|48);
    }
    inline bool cmp(soldier _,soldier __)
    {
    	return _.c<__.c;
    }
    void dfs(int l,int r)
    {
    	int i;
    	while(head[r]&&a[head[r]].d>=a[l].c+m)r=head[r];
    	/*cout<<l<<' '<<r<<' '<<head[r]<<' '<<a[l].c<<' '<<a[l].d<<' '<<a[r].c<<' '<<a[r].d<<endl;*/
    	if(a[r].d>=a[l].c+m)res[a[l].id]=dep[l]-dep[r]+1;
    	used[l]=1;
    	for(i=head[l];i;i=e[i].next)
    	{
    		head[l]=i;
    		dep[i]=dep[l]+1;
    		dfs(i,r);
    	}
    }
    signed main()
    {
    	int n,i,pos=1;
    	n=read(),m=read();
    	For(i,1,n)
    	{
    		a[i].c=read(),a[i].d=read();
    		a[i].id=i;
    		if(a[i].d<a[i].c)a[i].d+=m;
    		a[i+n].c=a[i].c+m;
    		a[i+n].d=a[i].d+m;
    	}
    	sort(a+1,a+(n<<1|1),cmp);
    	For(i,1,n<<1)
    	{
    		while(pos<n<<1&&a[pos+1].c<=a[i].d)pos++;
    		if(pos!=i)add(pos);
    		/*cout<<pos<<' '<<i<<' '<<head[pos]<<endl;*/
    	}
    	Down(i,n<<1,1)
    	if(!used[i])dfs(i,i);
    	For(i,1,n)write(res[i]),putchar(' ');
    	return 0;
    }
    
  • 相关阅读:
    混合式应用开发之AngularJS ng-repeat数组有重复值的解决方法
    混合式应用开发之串口通讯(2)
    混合式应用开发之串口通讯(1)
    第一篇博客
    win10出现"本地计算机上的MySQL57服务启动后停止"
    彻底区分html的attribute与dom的property
    Angularv4入门篇1
    node开发后将本地mysql数据导入到服务器mysql
    weex入门
    Color.js 方便修改颜色值
  • 原文地址:https://www.cnblogs.com/May-2nd/p/14756354.html
Copyright © 2011-2022 走看看