NOI ONLINE 提高组 序列

题目描述

小 D 有一个长度为 nn 的整数序列 a1na_{1 \dots n},她想通过若干次操作把它变成序列 bib_i

小 D 有 mm 种可选的操作,第 ii 种操作可使用三元组 (ti,ui,vi)(t_i,u_i,v_i) 描述:若 ti=1t_i=1,则她可以使 auia_{u_i}avia_{v_i} 都加一或都减一;若 ti=2t_i=2,则她可以使 auia_{u_i} 减一、avia_{v_i} 加一,或是 auia_{u_i} 加一、avia_{v_i} 减一,因此当 ui=viu_i=v_i 时,这种操作相当于没有操作。

小 D 可以以任意顺序执行操作,且每种操作都可进行无限次。现在给定序列与所有操作,请你帮她判断是否存在一种方案能将 aia_i 变为 bib_i。题目保证两个序列长度都为 nn。若方案存在请输出 YES,否则输出 NO

输入格式

本题输入文件包含多组数据。

第一行一个正整数 TT 表示数据组数。对于每组数据:

第一行两个整数 n,mn,m,表示序列长度与操作种数。

第二行 nn 个整数表示序列 aia_i

第三行 nn 个整数表示序列 bib_i

接下来 mm 行每行三个整数 ti,ui,vit_i,u_i,v_i,第 ii 行描述操作 ii

注意:同一个三元组 (ti,ui,vi)(t_i,u_i,v_i) 可能在输入中出现多次。

输出格式

对于每组数据输出一行一个字符串 YESNO 表示答案。

样例输入

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
3
1 1
1
3
1 1 1
2 3
1 2
4 5
1 1 2
2 1 2
1 1 2
3 3
1 2 3
5 5 4
1 1 2
1 1 3
2 2 3

样例输出

1
2
3
YES
YES
YES

提示

第一组数据:使用一次操作 11
第二组数据:使用三次操作 11
第三组数据:使用三次操作 11,令 a1,a2a_1,a_2 都增加 33,再使用一次操作 22,令 a1,a3a_1,a_3 都增加 11

数据范围

对于测试点 151 \sim 5n=2n=2m=1m=1ai,bi99a_i,b_i \le 99u1v1u_1 \ne v_1t1=1t_1=1
对于测试点 6106 \sim 10n=2n=2m=1m=1ai,bi99a_i,b_i \le 99u1v1u_1 \ne v_1t1=2t_1=2
对于测试点 111211 \sim 12n=2n=2ai,bi99a_i,b_i \le 99uiviu_i \ne v_i
对于测试点 131613 \sim 16ti=2t_i=2
对于测试点 1717n,m20n,m \le 20
对于测试点 1818n,m103n,m \le 10^3
对于所有测试点:1T101 \le T \le 101n,m1051 \le n,m \le 10^51ai,bi1091 \le a_i,b_i \le 10^9ti{1,2}t_i \in \{1,2\}1ui,vin1\le u_i,v_i \le n

分析

说实话第一眼看到这题的时候我有点懵,真不知道怎么做,不过一看数据,还好还好,暴力能拿一半分,于是我就真拿了一半分。。。。。

但某大佬说暴力能拿60,但我拿一半就满意了 我不会啊

考完后忍不住好奇这道题要怎么做,于是就看了看题解,发现题解也。。。有点难懂,主要是我看到一个字,图??这明明是个数的问题咋还和图扯上了关系,awsl,果然还是我太菜了

仔细读了一下,明白了一些。先看操作一:如果有(a1,a2)(a2,a3)(a3,a1),那么其中任意一个数都能自己加减二,如a1,a1+1,a2+1,a2-1,a3-1,a3+1,a1+1这样就能让a1自己加减二,同理a1换成任何数都可以,这里要注意,必须是奇数个点并且形成环才能这样办,所以每个奇数环上的数都能加减二,偶数个点为什么不行自己举个例子就明白了。再看操作二:如果有(a1,a2)(a2,a3)那么可以知道(a1,a3),a1+1,a2-1,a2+1,a3-1由此,a1+1,a3-1,可见操作二是具有传递性的,如果把它们看做是一个联通块,那么这个联通块可以任意加1,减1,所以如果这个联通块需要加的值和需要减的值一样,那么就满足。于是我们只要把每个操作二都缩成点,每个操作一建边,然后开始判断每块联通块是不是满足题意。

判断方法为,如果未形成奇数环,则需要使联通块内相加的数与相减的数相等,因为只能加一减一,否则使需要变化的总数是偶数即可,注意自环也要判断,因为自环相当于(a1,a2,1)(a1,a2,2)即a1+1,a2+1,a2-1,a1+1,这样也能使任意数加减二,

然后还有就是对于没有边连入的点,只有需要变化的值为0,才满足,因为没有边可以使它产生变化。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=2e5+10;
long long val[N];
struct Edge{
int to,next;
}e[N];
struct Node{
int t,u,v;
}p[N];
int Head[N],len,sum,flag;
void Ins(int a,int b){
e[++len].to=b;e[len].next=Head[a];Head[a]=len;
}
int f[N],belong[N],a[N],b[N];
int find(int x){
return f[x]==x?x:(f[x]=find(f[x]));
}
void Mer(int a,int b){
int u=find(a),v=find(b);
if(u!=v){
f[u]=v;val[v]+=val[u];//并查集缩点
}
}
void dfs(int x,int bin){
belong[x]=bin;
if(bin)sum+=val[x];
else sum-=val[x];
for(int i=Head[x];i;i=e[i].next){
int v=e[i].to;
if(belong[v]==-1)dfs(v,bin^1);//利用了^的性质
else if(belong[x]==belong[v])//说明v已经被提前访问过并且bin的值与x一样,那么就一定形成了奇数环
flag=1;
}
}
int main(){
// freopen("a.txt","r",stdin);
int t;
scanf("%d",&t);
while(t--){
int m,n,ans=1;len=0;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
for(int i=1;i<=n;i++)
scanf("%d",&b[i]),val[i]=b[i]-a[i];
for(int i=1;i<=n;i++)
f[i]=i,belong[i]=-1,Head[i]=0;
for(int i=1;i<=m;i++){
scanf("%d%d%d",&p[i].t,&p[i].u,&p[i].v);
if(p[i].t==2){
Mer(p[i].u,p[i].v);//合并操作二
}
}
for(int i=1;i<=m;i++){
if(p[i].t==1){
Ins(find(p[i].u),find(p[i].v));//这里已经缩点所以要合并根
Ins(find(p[i].v),find(p[i].u));
}
}
for(int i=1;i<=n;i++){
if(find(i)==i&&belong[i]==-1){
flag=sum=0;
dfs(i,0);
for(int x=Head[i];x;x=e[x].next){
if(e[x].to==i)flag=1;//自环
}
if(Head[i]==0&&sum!=0)ans=0;//没有边连入
else if(flag==1&&sum%2!=0)ans=0;//奇数环
else if(flag==0&&sum!=0)ans=0;//偶数环
}
}
if(ans)printf("YES\n");
else printf("NO\n");
}
}

NOI ONLINE 提高组 序列
https://suzipei.github.io/2020/03/08/noionline/
作者
Su_Zipei
发布于
2020年3月8日
许可协议