• Tunnel Warfare (HDU


    在抗日战争期间,华北平原广大地区进行了大规模的隧道战。 一般来说,通过隧道连接的村庄排成一列。 除了两端,每个村庄都与两个相邻的村庄直接相连。
    入侵者经常对一些村庄发动袭击并摧毁其中的部分隧道。 八路军指挥官要求最新的隧道和村庄连接状态。 如果某些村庄严重隔离,必须立即恢复连接!

    Input
    输入的第一行包含两个正整数n和m(n,m≤50,000),表示村庄和事件的数量。 接下来的m行中的每一行描述一个事件。

    以下所示的不同格式描述了三种不同的事件:
    D x:第x个村庄被毁。
    Q x:指挥官询问第x个村庄与其直接或间接相关的村庄数量。
    R:最后毁坏的村庄被重建了。

    Output
    按顺序输出每个指挥官询问的答案。

    Sample Input
    7 9
    D 3
    D 6
    D 5
    Q 4
    Q 5
    R
    Q 4
    R
    Q 4
    Sample Output
    1
    0
    2
    4

    思路:
    如果村庄x被摧毁,那与他相连的村庄就是0个,如果没有被摧毁那么就等于,x左边第一个被摧毁村庄到x右边第一个被摧毁村庄之间的村庄的数量,很容易就可以想到用线段树可以做,直接上代码:

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int N=50010;
    int n,m,a[N];//a[x]==1,表示x没有被摧毁
    struct node
    {
    	int l,r,sum;//sum区间[l,r]之间没被摧毁的村庄的数量
    }tr[N<<2];
    void pushup(int rt)
    {
    	tr[rt].sum=tr[rt<<1].sum+tr[rt<<1|1].sum;
    }
    void build(int rt,int l,int r)
    {
    	if(l==r) tr[rt]={l,r,1},a[l]=1;
    	else 
    	{
    		tr[rt]={l,r};
    		int mid = l+r>>1;
    		build(rt<<1,l,mid);
    		build(rt<<1|1,mid+1,r);
    		pushup(rt);
    	}
    }
    void updata(int rt,int x,int d)
    {
    	if(tr[rt].l==x&&tr[rt].r==x) a[x]=tr[rt].sum=d;
    	else
    	{
    		int mid =tr[rt].l+tr[rt].r>>1;
    		if(x<=mid) updata(rt<<1,x,d);
    		else updata(rt<<1|1,x,d);
    		pushup(rt);
    	}
    }
    int query(int rt,int l,int r)//查询[l,r]之间被被摧毁村庄的数量
    {
    	if(tr[rt].l>=l&&tr[rt].r<=r) return tr[rt].sum;
    	int mid =tr[rt].l+tr[rt].r>>1,res=0;
    	if(l<=mid) res+=query(rt<<1,l,r);
    	if(r>mid) res+=query(rt<<1|1,l,r);
    	return res;
    }
    int query1(int rt,int x)//查询x左边第一个被摧毁的村庄的坐标
    {
    	if(tr[rt].l==tr[rt].r) return (tr[rt].sum==1?0:tr[rt].l);//这个节点没被摧毁就返回0,最小的点,最终的答案可能在这个节点左或者右,返回0,一定不影响答案。
    	int mid= tr[rt].l+tr[rt].r>>1;
    	if(x>mid) 
    	{
    		if(query(1,mid+1,x)==x-mid) return query1(rt<<1,mid);//如果mid到x都没被摧毁,第一个被摧毁的村庄一定在mid左边
    		else return max(query1(rt<<1,mid),query1(rt<<1|1,x));//否则取最大值,就是离x最近的
    	}
    	else 
    	{
    		return query1(rt<<1,x);//x<=mid,一定在[tr[rt].l,x]
    	}
    }
    int query2(int rt,int x)//查询x右边第一个被摧毁的村庄
    {
    	if(tr[rt].l==tr[rt].r) return (tr[rt].sum==1?n+1:tr[rt].l);//与上面一样,n+1不影响结果
    	int mid= tr[rt].l+tr[rt].r>>1;
    	if(x<=mid) 
    	{
    		if(query(1,x,mid)==mid-x+1) return query2(rt<<1|1,mid+1);//一定在mid+1右边
    		else return min(query2(rt<<1,x),query2(rt<<1|1,mid+1));//在x右边就得取最小值
    	}
    	else 
    	{
    		return query2(rt<<1|1,x);//在x以右
    	}
    }
    int main()
    {
    	while(~scanf("%d%d",&n,&m))
    	{
    		build(1,1,n);
    		stack<int> st;
    		while(m--)
    		{
    			char op[2];
    			scanf("%s",op);
    			int x;
    			if(*op=='D') 
    			{
    				scanf("%d",&x); 
    				st.push(x);//用栈存储被摧毁的村庄
    				updata(1,x,0);
    			}
    			else if(*op=='Q')
    			{
    				scanf("%d",&x);
    				if(a[x]) printf("%d
    ",query2(1,x)-1-query1(1,x));
    				else puts("0");
    			}
    			else if(st.size())
    			{
    				updata(1,st.top(),1);
    				st.pop();
    			}
    		}
    	}
    }
    

    看了个大佬的代码,思路是一样的,用红黑树去求只用了265ms,上面哪个是1800+ms,

    #include<bits/stdc++.h>
    using namespace std; 
    int n,m;
    int main()
    {
    	while(~scanf("%d%d",&n,&m))
    	{
    		char op[2];
    		int x;
    		stack<int> st; set<int> stt;//都保存被摧毁的村庄
    		stt.insert(0);//预处理边界,避免麻烦
    		stt.insert(n+1);
    		while(m--)
    		{
    			scanf("%s",op);
    			if(*op=='D')
    			{
    				scanf("%d",&x);
    				st.push(x);
    				stt.insert(x);//将x插入
    			}
    			else if(*op=='Q')
    			{
    				scanf("%d",&x);
    				if(stt.find(x)!=stt.end()) puts("0");//x没被摧毁
    				else
    				{
    					auto l=stt.upper_bound(x);//返回最小的大于x的被摧毁村庄,就是x右边第一个被摧毁村庄,lower_bound()是一样的因为stt里面没有x
    					auto r=l--;//再减1就是最大的小于x的被摧毁村庄
    					printf("%d
    ",*r-*l-1);
    				}
    			}
    			else if(st.size())
    			{
    				stt.erase(st.top());
    				st.pop();
    			}
    		}
    	}
    	return 0;
    }
    
  • 相关阅读:
    星时代曹波涛:分享一个测试数据生成的工具
    myabtis-plus 分页
    吴恩达机器学习_55过拟合问题/56代价函数
    吴恩达机器学习_51高级优化/52多元分类:一对多
    吴恩达机器学习_49代价函数/50简化代价函数与梯度
    吴恩达机器学习_46分类/47假设函数/48决策边界
    Windows10下安装VMware workstation 15.1虚拟机+配置Ubuntu16系统
    编程作业ex1:附加练习
    编程作业ex1:线性回归
    吴恩达机器学习_43矢量
  • 原文地址:https://www.cnblogs.com/neflibata/p/12871750.html
Copyright © 2020-2023  润新知