2 条题解

  • 0
    @ 2025-8-28 0:01:54

    题目描述

    扶苏是洛谷王国的航空局长,她掌管着洛谷境内一切民航飞机的航线安排。

    洛谷王国共有nn座城市,从11nn编号。任意两座城市之间都有一条双向航线。但不一定每条航线都有航班经过。

    初始时,每条航线上都没有航班。在接下来mm天里,扶苏会根据对人们出行需求的预测,在若干天内向一些航线上添加航班,并做出一些查询。

    每次添加航班的格式是:uu vv xx yy,表示在城市uu和城市vv的航线上添加xx个航班,这条命令会在yy天后取消。即给从增加命令下达当天到下达后第y1y−1天这yy天里uuvv的航线添加xx个航班。在第yy天不再添加xx个航班。可能会有多个命令影响同一天的航班数,这些命令可以叠加生效。

    对于一个城市uu,称uu的“主要出行目的地”是当前时刻与uu之间的航线上航班数最多的城市(如果存在多个这样的城市,取编号最小的);特别的,如果u与任何城市之间的航线上航班数均为00,称uu是一个“封闭城市”,且它没有“主要出行目的地”;如果两座城市互为主要出行目的地”,称他们是“交流城市对**”。

    每天开始时,扶苏会先下达若干条添加航班的命令。在处理完这些命令后,你会收到若干个查询某个城市的“主要出行目的地”的请求。此外,你还.可.能希望求出此时的“封闭城市”和“交流城市对”各有多少。

    请你帮助处理扶苏下达的添加航班的指令,并回答她的询问

    输入格式

    第一行是两个整数,依次表示城市数量nn和天数mm

    接下来3m3m行,每三行一组描述一天中的事件,格式如下:

    • 第一行:首先是一个整数kik_i,表示当天下达添加航班的命令数。接下来有4ki4k_i个整数,依次表示这kik_i条命令。格式见【题目描述】。

    • 第二行:首先是一个整数 lil_i,表示当天查询“主要出行目的地”的数量。接下来 lil_i 个整数,依次表示每次查询的对象。

    • 第三行:只有两个整数 pip_i,qiq_i,取值均为0011。分别表示当天是否需要查询“封闭城市”和“交流城市对”的数量。如果 pi=1p_i=1,表示查询”封闭城市“的数量,如果 pi=0p_i=0,表示不需要查询;qi的含义同理

    输入样例

    3 3
    2 1 2 2 3 1 3 3 2
    1 1
    0 0
    1 2 3 3 1
    2 1 2
    0 1
    0
    2 1 3
    1 1
    

    输出样例

    3
    3
    3
    1
    2
    0
    1
    1
    

    数据范围

    1i=1mki2×1051 \le \sum_{i=1}^{m}k_i \le 2\times10^5 1i=1mli2×1051 \le \sum_{i=1}^{m}l_i \le 2 \times 10^5 1n,m1051 \le n,m \le 10^5 1A,B2×105 1 \le A,B \le 2×10^5 1u,vn1 \le u,v \le n 1x1091 \le x \le 10^9 1ym1\le y \le m uvu \ne v

    以下为题解

    思路

    首先对于每个城市,它的 主要出行目的地 即为到其他城市的航线中航班最多的那一个。

    考虑使用线段树来维护。

    显然,用朴素的线段树无论空间或是时间都不能满足.但由于 kik_ilil_i 的总和最大只到 2e52e5 我们可以使用动态开点线段树来进行维护。

    对于第 ii 天的每组 u,v,x,yu,v,x,y 在第 ii 天增加 xx 并在第 i+yi+y 天减去 xx,维护 1n1 \sim n 城市的最大值。

    因为我们查询的总是 1n1 \sim n 中的最大值,所以区间查询的值就是根节点的值

    接着是维护 封闭城市 这一项。

    一个城市为封闭城市,当且仅当它所有航线的航班均为零。

    我们可以在每次修改后查询最大值并维护。

    交流城市对 这一项会变化有两种情况:

    1. 原来不是城市对的,现在变为了城市对
    2. 原来是城市对的,现在不再是城市对

    我们可以在每次修改后查询最大值的城市编号并维护。

    时间复杂度 O(i=1mkilogn)O(\sum_{i=1}^{m}{k_i}\log n)

    代码

    #include<bits/stdc++.h>
    using namespace std;
    const int N=2e5+5;
    struct node{
    	int data,id,l,r,ls=-1,rs=-1;
    }tr[N*2*18];
    int n,m,idx;
    struct oper{
    	int u,v,x;
    }; 
    vector<oper> op[N]; 
    void push_up(int u)
    {
    	int maxn,id;
    	if(tr[u].ls!=-1&&tr[u].rs==-1)
    		maxn=tr[tr[u].ls].data,id=tr[tr[u].ls].id;
    	else if(tr[u].ls==-1&&tr[u].rs!=-1)
    		maxn=tr[tr[u].rs].data,id=tr[tr[u].rs].id;
    	else if(tr[tr[u].ls].data>=tr[tr[u].rs].data)
    		maxn=tr[tr[u].ls].data,id=tr[tr[u].ls].id;
    	else
    		maxn=tr[tr[u].rs].data,id=tr[tr[u].rs].id;
    	tr[u].data=maxn,tr[u].id=id;
    }
    void modify(int u,int x,int k)//单点修改+动态开点
    {
    	if(tr[u].l==x&&tr[u].r==x)
    	{
    		tr[u].id=tr[u].l;
    		tr[u].data+=k;
    		if(tr[u].data==0)
    			tr[u].id=0;
    		return;
    	}
    	int mid=(tr[u].l+tr[u].r)>>1;
    	if(x<=mid)
    	{
    		if(tr[u].ls==-1)
    		{
    			tr[u].ls=++idx;
    			tr[idx].l=tr[u].l;
    			tr[idx].r=mid;
    		}
    		modify(tr[u].ls,x,k);
    	}else
    	{
    		if(tr[u].rs==-1)
    		{
    			tr[u].rs=++idx;
    			tr[idx].l=mid+1;
    			tr[idx].r=tr[u].r;
    		}
    		modify(tr[u].rs,x,k);
    	}
    	push_up(u); 
    }
    int no_out,city_dui;
    bool has_out[N],add_dui[N];
    void check(int u,int l_id)
    {
      //维护封闭城市
    	if(!has_out[u]&&tr[u].data)
    	{
    		has_out[u]=1;
    		no_out--;
    	}
    	if(has_out[u]&&(!tr[u].data))
    	{
    		has_out[u]=0;
    		no_out++;
    	}
      //维护交流城市对
    	if(tr[l_id].id==u&&tr[u].id!=l_id)
    	{
    		city_dui--;
    		add_dui[u]=0;
    		add_dui[l_id]=0;
    	}
    	if(tr[tr[u].id].id==u&&!add_dui[tr[u].id])	
    	{
    		city_dui++;
    		add_dui[u]=1;
    		add_dui[tr[u].id]=1;
    	}
    	
    } 
    int main()
    {
    	scanf("%d%d",&n,&m);
    	no_out=n,city_dui=0;
    	for(int i=1;i<=n;i++)
    	{
        //初始化n个根节点
    		tr[++idx].data=0;
    		tr[idx].l=1;
    		tr[idx].ls=-1;
    		tr[idx].r=n;
    		tr[idx].rs=-1;
    	}
    	for(int i=1;i<=m;i++)
    	{
    		int k;
    		scanf("%d",&k);
    		while(k--)
    		{
    			int u,v,x,y;
    			scanf("%d%d%d%d",&u,&v,&x,&y);
    			if(i+y<=m) //在第i+y天减掉
    				op[i+y].push_back({u,v,x});
    			int l_id=tr[u].id;
    			modify(u,v,x);
    			check(u,l_id);
    			l_id=tr[v].id;
    			modify(v,u,x);
    			check(v,l_id);
    		}
    		int vs=op[i].size();
    		if(vs!=0)
    		{
    			for(int k=vs-1;k>=0;k--)
    			{
    				int l_id=tr[op[i][k].u].id;
    				modify(op[i][k].u,op[i][k].v,-op[i][k].x);
    				check(op[i][k].u,l_id);
    				l_id=tr[op[i][k].v].id;
    				modify(op[i][k].v,op[i][k].u,-op[i][k].x);
    				check(op[i][k].v,l_id);
    				op[i].pop_back();
    			}
    		}
        // O(1)查询
    		int l;
    		scanf("%d",&l);
    		while(l--)
    		{
    			int x;
    			scanf("%d",&x);
    			printf("%d\n",tr[x].id);
    		}
    		int p,q;
    		scanf("%d%d",&p,&q);
    		if(p)
    			printf("%d\n",no_out);
    		if(q)
    			printf("%d\n",city_dui); 
    	}
    	return 0;
    }
    
    
    nm的syc 调你代码调了两个半小时\color{white}{\text{nm的syc 调你代码调了两个半小时}}

    信息

    ID
    926
    时间
    1000ms
    内存
    256MiB
    难度
    8
    标签
    (无)
    递交数
    34
    已通过
    6
    上传者