ZROI - 20连测day2

最新推出 模式。

比赛链接:http://zhengruioi.com/contest/1465


A. 花菖蒲

题目简介

给定 ,判断是否存在一棵树有恰好 个结点度数为 ,有 个结点度数为 ;要求这棵树的结点个数不超过 。或报告无解。

数据范围:

考虑到有一个 ,那我们考虑这种情况。

我们想到了二叉树,对于一棵二叉树,其根结点度数为 ,叶结点度数为 ,而其余结点度数为 。然后我们随便画画,发现对于一棵拥有 个叶结点的二叉树,正好有 个结点度数为 ,也就是 个结点。

所以我们的思路是正确的,所以通过这个方式我们扩展

首先我们考虑 的情况,也就是保证 个叶结点的同时中间要足够多,然后你发现样例中 时无解,所以我们大胆猜测,在 时一概无解。

关于证明,我们从总度数来考虑,一棵树的总度数为 ,然后我们加入一个 度点,那么平均度数就是 。但如果 ,所以 度点小于 度点,而无论如何都不可能让平均度数小于 了。所以必然无解。

然后考虑 的情况,你发现你可以直接选择 中构造的某一个叶结点提取出来,然后把所有还需要插入进去的 度点全部连接到这个点上,也就是构成一个菊花子图。

但是你发现当 的时候,下面的菊花图子结点有 个,会形成一个新的 度点,然后你发现样例中 无解。所以这种情况无解。

时间复杂度 ,瓶颈在于输出。考场特别脑抽,本来是对的,结果改错怒挂

AC Code
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
79
80
81
// ----- Eternally question-----
// Problem: A. 【noip赛前20天冲刺集训 day2】花菖蒲
// Contest: ZROI - 23noip赛前20天冲刺 day2
// URL: http://zhengruioi.com/contest/1465/problem/2720
// Memory Limit: 1024 MB
// Time Limit: 1000 ms
// Written by: Eternity
// Time: 2023-10-10 08:37:33
// ----- Endless solution-------

#include<bits/stdc++.h>
#define re register
typedef long long ll;
template<class T>
inline void read(T &x)
{
x=0;
char ch=getchar(),t=0;
while(ch<'0'||ch>'9') t|=ch=='-',ch=getchar();
while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
if(t) x=-x;
}
template<class T,class ...T1>
inline void read(T &x,T1 &...x1){ read(x),read(x1...); }
template<class T>
inline void write(T x)
{
if(x<0) putchar('-'),x=-x;
if(x>9) write(x/10);
putchar(x%10+'0');
}
template<>
inline void write(bool x){ putchar(x?'1':'0'); }
template<>
inline void write(char c){ putchar(c); }
template<>
inline void write(char *s){ while(*s!='\0') putchar(*s++); }
template<>
inline void write(const char *s){ while(*s!='\0') putchar(*s++); }
template<class T,class ...T1>
inline void write(T x,T1 ...x1){ write(x),write(x1...); }
template<class T>
inline bool checkMax(T &x,T y){ return x<y?x=y,1:0; }
template<class T>
inline bool checkMin(T &x,T y){ return x>y?x=y,1:0; }
const int MAXN=2e2+10;
int A,B,Idx;
inline void solve1()
{
int bit=0;
while((1<<bit)<A) ++bit;
Idx=(1<<(bit+1))-1;
Idx+=(A-(1<<bit))*2;
write(Idx,'\n');
for(int i=2;i<=Idx;++i) write(i>>1,' ',i,'\n');
}
inline void solve2()
{
int bit=0,_A=B+2;
while((1<<bit)<_A) ++bit;
Idx=(1<<(bit+1))-1;
Idx+=(_A-(1<<bit))*2;
write(Idx+(A-B-1),'\n');
for(int i=2;i<=Idx;++i) write(i>>1,' ',i,'\n');
for(int i=1;i<=A-B-1;++i) write(Idx,' ',Idx+i,'\n');
}
int main()
{
// freopen(".in","r",stdin);
// freopen(".out","w",stdout);
read(A,B);
if(A==0&&B==0) return puts("1"),0;
if(A<B+2) return puts("0"),0;
if(A==B+2) solve1();
else if(A==B+3) return puts("0"),0;
else solve2();
return 0;
}
/*

*/

B. 百日草

题目简介

给定一个有 个结点 条边的有向图,边带权。设一条路径依次经过的边的边权为 ,那么这条路径的权值为

现在请找到一条从 的路径使得权值最小。

数据范围:

考虑到这个贡献是单调的,所以我们二分出一个 ,然后对整张图作最短路,但是跳过所有 的转移,然后判断是否能够转移到 即可。

最短路,所以时间复杂度 ,但是边权只有 ,所以直接 ,时间复杂度 。然后考场上有人写的线性,也就是一遍搜索动态维护权值,时间复杂度

AC Code
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
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
// ----- Eternally question-----
// Problem: B. 【noip赛前20天冲刺集训 day2】百日草
// Contest: ZROI - 23noip赛前20天冲刺 day2
// URL: http://zhengruioi.com/contest/1465/problem/2721
// Memory Limit: 1024 MB
// Time Limit: 1000 ms
// Written by: Eternity
// Time: 2023-10-10 19:28:40
// ----- Endless solution-------

#include<bits/stdc++.h>
#define re register
typedef long long ll;
template<class T>
inline void read(T &x)
{
x=0;
char ch=getchar(),t=0;
while(ch<'0'||ch>'9') t|=ch=='-',ch=getchar();
while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
if(t) x=-x;
}
template<class T,class ...T1>
inline void read(T &x,T1 &...x1){ read(x),read(x1...); }
template<class T>
inline void write(T x)
{
if(x<0) putchar('-'),x=-x;
if(x>9) write(x/10);
putchar(x%10+'0');
}
template<>
inline void write(bool x){ putchar(x?'1':'0'); }
template<>
inline void write(char c){ putchar(c); }
template<>
inline void write(char *s){ while(*s!='\0') putchar(*s++); }
template<>
inline void write(const char *s){ while(*s!='\0') putchar(*s++); }
template<class T,class ...T1>
inline void write(T x,T1 ...x1){ write(x),write(x1...); }
template<class T>
inline bool checkMax(T &x,T y){ return x<y?x=y,1:0; }
template<class T>
inline bool checkMin(T &x,T y){ return x>y?x=y,1:0; }
const int MAXN=3e5+10;
const ll INF=3e14;
int N,M;
struct G
{ int next,to,val; }Edge[MAXN<<1];
int Head[MAXN],Total;
inline void addEdge(int u,int v,int w)
{
Edge[++Total]=(G){Head[u],v,w};Head[u]=Total;
// Edge[++Total]=(G){Head[v],u,w};Head[v]=Total;
}
bool Vis[MAXN];
ll Dist[MAXN];
inline bool Bfs(ll lim)
{
for(int i=1;i<=N;++i) Dist[i]=INF,Vis[i]=0;
std::queue<int>Q;
Q.push(1),Dist[1]=0;
while(!Q.empty())
{
int u=Q.front();Q.pop();
if(Vis[u]) continue;
Vis[u]=1;
for(int e=Head[u],v;e;e=Edge[e].next)
{
v=Edge[e].to;
if((Dist[u]+1)*Edge[e].val<=lim) (checkMin(Dist[v],Dist[u]+1))&&(Q.push(v),1);
}
}
return Vis[N];
}
signed main()
{
// freopen(".in","r",stdin);
// freopen(".out","w",stdout);
read(N,M);
for(int i=1,u,v,w;i<=M;++i) read(u,v,w),addEdge(u,v,w);
ll l=0,r=INF,res=INF;
while(l<=r)
{
ll mid=(l+r)>>1;
if(Bfs(mid)) r=mid-1,res=mid;
else l=mid+1;
}
write(res,'\n');
return 0;
}
/*

*/

C. 紫丁香

题目简介

给定一个有 个结点 条边的无向图,现在要求你保留一些边,删除一条边,并使最后留下来的图中度数为奇数的结点个数最大。

将边的状态设为 串(保留为 ,删除为 ),求出字典序最大的方案。

数据范围:

考虑数据点以 的形式给出,所以我们分讨的 的奇偶性。

我们首先考虑树的情况,我们做一个树型 式的搜索,对于每个结点考虑其与父结点的连边是否断掉,然后你发现这个决策独立,所以直接贪心选择即可。最后我们得到结论,当 时,答案为 ,否则为 ,因为当 是奇数时,可能会存在根结点并不满足。

然后考虑图的情况,我们考虑图的编号最大生成树,然后在生成树上做树的情况,然后你发现非树边不会影响树边的决策,所以非树边一定不会被删掉。

花花维护了一个线段树我并不太清楚是干什么的。我把代码放下面大家可以研究研究。时间复杂度

AC Code
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
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
// ----- Eternally question-----
// Problem: C. 【noip赛前20天冲刺集训 day2】紫丁香
// Contest: ZROI - 23noip赛前20天冲刺 day2
// URL: http://zhengruioi.com/contest/1465/problem/2722
// Memory Limit: 1024 MB
// Time Limit: 1000 ms
// Written by: Eternity
// Time: 2023-10-10 10:12:43
// ----- Endless solution-------

#include<bits/stdc++.h>
#define re register
typedef long long ll;
template<class T>
inline void read(T &x)
{
x=0;
char ch=getchar(),t=0;
while(ch<'0'||ch>'9') t|=ch=='-',ch=getchar();
while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
if(t) x=-x;
}
template<class T,class ...T1>
inline void read(T &x,T1 &...x1){ read(x),read(x1...); }
template<class T>
inline void write(T x)
{
if(x<0) putchar('-'),x=-x;
if(x>9) write(x/10);
putchar(x%10+'0');
}
template<>
inline void write(bool x){ putchar(x?'1':'0'); }
template<>
inline void write(char c){ putchar(c); }
template<>
inline void write(char *s){ while(*s!='\0') putchar(*s++); }
template<>
inline void write(const char *s){ while(*s!='\0') putchar(*s++); }
template<class T,class ...T1>
inline void write(T x,T1 ...x1){ write(x),write(x1...); }
template<class T>
inline bool checkMax(T &x,T y){ return x<y?x=y,1:0; }
template<class T>
inline bool checkMin(T &x,T y){ return x>y?x=y,1:0; }
const int MAXN=6e5+10,MAXM=9e5+10;
int N,M,ans,Pool[MAXN];
struct Edges
{ int fr,to; }Ed[MAXM];
struct Node
{
int u,v;
std::vector<int>vec;
}a[MAXM];
bool Del[MAXM];
struct DSU
{
int Rt[MAXN],Siz[MAXN];
std::vector<int>vec[MAXN];
void build(int n){ for(int i=1;i<=n;++i) Rt[i]=i,Siz[i]=1,vec[i].push_back(i); }
int getRt(int x)
{
while(x!=Rt[x]) x=Rt[x];
return x;
}
void merge(int u,int v,int id)
{
int p=getRt(u),q=getRt(v);
if(p==q) return ;
if(vec[p].size()<vec[q].size()) std::swap(p,q);
ans-=Siz[p]+Siz[q],Rt[q]=p,Siz[p]^=Siz[q],ans+=Siz[p];
a[id]=(Node){p,q};
for(int x:vec[q]) vec[p].push_back(x),a[id].vec.push_back(x);
}
void back(int id)
{
int p=a[id].u,q=a[id].v;
if(!p) return ;
ans-=Siz[p],Rt[q]=q,Siz[p]^=Siz[q];
for(int x:a[id].vec) Siz[p]^=Pool[x],Siz[q]^=Pool[x];
ans+=Siz[p]+Siz[q];
}
inline void calc(int id,int x,int y)
{
Pool[Ed[id].fr]^=1,Pool[Ed[id].to]^=1;
ans-=Siz[x]+Siz[y],Siz[x]^=1,Siz[y]^=1,ans+=Siz[x]+Siz[y];
}
}Dsu;
int main()
{
// freopen(".in","r",stdin);
// freopen(".out","w",stdout);
read(N,M);
for(int i=1,u,v;i<=M;++i) read(u,v),Ed[i]=(Edges){u+1,v+1};
Dsu.build(N);ans=N;
for(int i=M;i;--i) Dsu.merge(Ed[i].fr,Ed[i].to,i);
int mx=N-ans;
for(int i=1;i<=M;++i)
{
Dsu.back(i);
int p=Dsu.getRt(Ed[i].fr),q=Dsu.getRt(Ed[i].to);
Dsu.calc(i,p,q);
if(N-ans<mx) Del[i]=1,Dsu.calc(i,p,q);
}
for(int i=1;i<=M;++i) putchar(1-Del[i]+'0');
return 0;
}
/*

*/
AC Code
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
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
#include <bits/stdc++.h>

template <int T>
struct fast_io
{
char ib[T], ob[T], * p1, * p2, * q1, * q2;
fast_io()
{
p1 = p2 = ib;
q1 = ob;
q2 = ob + T;
}
inline char gc()
{
return p1 == p2 && (p2 = (p1 = ib) + fread(ib, 1, T, stdin), p1 == p2) ? EOF : *p1++;
}
inline void pc(char ch)
{
if (q1 == q2) q2 = (q1 = ob) + fwrite(ob, 1, T, stdout);
*q1++ = ch;
}
~fast_io()
{
fwrite(ob, 1, q1 - ob, stdout);
}
};
fast_io<1000000> io;

inline int read()
{
int res = 0, neg = 1;
char ch;
do
{
ch = io.gc();
if (ch == '-') neg = -1;
} while (ch < 48 || ch > 57);
do res = res * 10 + ch - 48, ch = io.gc(); while (ch >= 48 && ch <= 57);
return res * neg;
}

inline void putint(int x)
{
if (x < 0)
{
io.pc('-');
putint(-x);
return;
}
if (x / 10) putint(x / 10);
io.pc(48 + x % 10);
}

inline void output(int x, char ch = ' ')
{
putint(x);
io.pc(ch);
}

const int N = 1e6 + 50;

int n, m, f[N], fa[N], par_e[N], jmp[N], deg[N], nu[N], nv[N];
bool del[N];
std::vector<int> G[N], id[N], H[N];

inline int find(int x)
{
while (x != f[x])
x = f[x] = f[f[x]];
return x;
}

void dfs(int x, int f = 0)
{
fa[x] = f;
for (int i = 0; i < G[x].size(); ++i)
{
int y = G[x][i], z = id[x][i];
if (y != f)
{
par_e[y] = z;
jmp[z] = par_e[x];
dfs(y, x);
if (!(deg[y] & 1))
{
--deg[y], --deg[x];
del[z] = true;
}
}
}
}

struct segment_t
{
static const int n = 6e5;
int min[N << 2], va[N], cnt;
inline int lc(int o) { return o << 1; }
inline int rc(int o) { return o << 1 | 1; }
segment_t()
{
memset(min, 0x3f, sizeof min);
}
void push_up(int o)
{
min[o] = std::min(min[lc(o)], min[rc(o)]);
}
void modify(int o, int l, int r, int p, int v)
{
if (l == r)
{
min[o] = v;
}
else
{
const int mid = l + r >> 1;
if (p <= mid) modify(lc(o), l, mid, p, v);
else modify(rc(o), mid + 1, r, p, v);
push_up(o);
}
}
int query(int o, int l, int r, int v)
{
if (min[o] >= v) return -1;
if (l == r) return l;
const int mid = l + r >> 1;
if (min[rc(o)] < v) return query(rc(o), mid + 1, r, v);
return query(lc(o), l, mid, v);
}
int query(int v)
{
int t = query(1, 1, n, v);
if (t == -1) return -1;
return va[t];
}
void push(int x)
{
modify(1, 1, n, ++cnt, x);
va[cnt] = x;
}
int top()
{
return va[cnt];
}
void pop()
{
modify(1, 1, n, cnt--, 0x3f3f3f3f);
}
bool empty()
{
return cnt == 0;
}
} st;

void constructRelation(int x, int f = 0)
{
for (int i = 0; i < G[x].size(); ++i)
{
int y = G[x][i], z = id[x][i];
if (y != f)
{
int t = st.query(z);
if (t == -1) H[m + 1].push_back(z);
else H[t].push_back(z);
st.push(z);
constructRelation(y, x);
st.pop();
}
}
}

int moveStatus(int x, int f = 0)
{
int cur = -1;
for (int y : H[x])
{
if ((cur == -1 || y < cur) && del[y])
{
cur = y;
}
}
if (cur == -1) return -1;
int t = moveStatus(cur, x);
if (t == -1) return cur;
return t;
}

int main()
{
n = read(), m = read();
for (int i = 1; i <= n; ++i) f[i] = i;
for (int i = 1; i <= m; ++i)
{
nu[i] = read() + 1, nv[i] = read() + 1;
}
for (int i = 1; i <= m; ++i)
{
int u = nu[m - i + 1], v = nv[m - i + 1];
++deg[u], ++deg[v];
int fu = find(u), fv = find(v);
if (fu != fv)
{
f[fu] = fv;
G[u].push_back(v); id[u].push_back(m - i + 1);
G[v].push_back(u); id[v].push_back(m - i + 1);
}
}
dfs(1);
if (n & 1)
{
constructRelation(1);
int rt = m + 1;
int z = moveStatus(rt);
if (z != -1)
{
while (z) del[z] ^= 1, z = jmp[z];
}
}
for (int i = 1; i <= m; ++i) io.pc(49 - del[i]);
return 0;
}


D. 麒麟草

题目简介

给定一个 的平面,其中有 个矩形,现在给出 个询问,每次询问一个给定矩形 与这 个矩形面积并的面积交。强制在线。

数据范围:

很离谱,我记得之前某道省选模拟( 月份有一个叫 的题好像)就想写矩阵面积并区间查询,但是发现转化前缀和的时候需要维护区间非零位置的历史版本和,触及到知识盲区了考场上胡了 没胡出来。

现在回旋镖打回来了,为偷懒谢罪。

首先考虑离线,那么扫描线维护面积并的历史版本和,然后离散化一下即可。

然后考虑实际上是半在线,只有询问在线,我们依然可以把 个矩形处理出来,所以这里需要可持久化,虽然吉司机线段树的时间复杂度的分析涉及到均摊,理论无法可持久化,但是因为每个版本仅涉及到 次修改,所以这个操作是正确的。然后就是区间修改主席树,如果要下放标记会有 的空间常数,可能会被卡常,所以标记永久化。

然后考虑查询时仅离散化了修改,所以查询端点可能并不在离散化序列中,我们设前驱后继为 ,因为这个区间连续且均等,所以我们可以考虑直接做一个前缀和和后缀和,同样将 拆分,分类讨论后得到 种边界,然后就可以直接做了。

大常数

代码没时间写,最近事多。

AC Code
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
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
#include <bits/stdc++.h>
using namespace std;
using i64 = long long;
using i128 = __int128_t;
constexpr int maxm = 3e7;
vector<int> sx, sy;
struct Segment {
struct Node {
int mn, mncnt, ls, rs;
int del, tag;
i64 mnsum;
}a[maxm];
struct info {
int mn, mncnt; i64 mnsum;
friend info operator + (info x, info y) {
info z;
z.mn = min(x.mn, y.mn); z.mnsum = x.mnsum + y.mnsum;
if(x.mn < y.mn) z.mncnt = x.mncnt;
else if(x.mn > y.mn) z.mncnt = y.mncnt;
else z.mncnt = x.mncnt + y.mncnt;
return z;
}
info apply(int del, int tag, int is) {
return {mn + del, mncnt, mnsum + (mn + del == is ? 1ll * tag * mncnt: 0) };
}
};
int cnt;
inline int newnode(int u) {
int cur = ++ cnt;
assert(cnt < maxm - 10);
a[cur] = a[u];
return cur;
}
inline void seta(int u, int del, int tag, int is) {
a[u].del += del;
a[u].mn += del;
if(a[u].mn == is) {
a[u].mnsum += 1ll * a[u].mncnt * tag;
a[u].tag += tag;
}
}
inline void dw(int u) {
a[u].ls = newnode(a[u].ls);
seta(a[u].ls, a[u].del, a[u].tag, a[u].mn);
a[u].rs = newnode(a[u].rs);
seta(a[u].rs, a[u].del, a[u].tag, a[u].mn);
a[u].del = a[u].tag = 0;
}
inline void up(int u) {
a[u].mn = min(a[a[u].ls].mn, a[a[u].rs].mn);
if(a[a[u].ls].mn < a[a[u].rs].mn) a[u].mncnt = a[a[u].ls].mncnt;
else if(a[a[u].ls].mn > a[a[u].rs].mn) a[u].mncnt = a[a[u].rs].mncnt;
else a[u].mncnt = a[a[u].ls].mncnt + a[a[u].rs].mncnt;
}
void update(int &u, int l, int r, int ql, int qr, int k) {
u = newnode(u);
if(l >= ql && r <= qr) return seta(u, k, 0, 0);
int mid = l + r >> 1; dw(u);
if(qr <= mid) update(a[u].ls, l, mid, ql, qr, k);
else if(ql > mid) update(a[u].rs, mid + 1, r, ql, qr, k);
else update(a[u].ls, l, mid, ql, qr, k), update(a[u].rs,mid + 1, r, ql, qr, k);
up(u);
}
info query(int u, int l, int r, int ql, int qr) {
if(l >= ql && r <= qr) return info{a[u].mn, a[u].mncnt, a[u].mnsum};
int mid = l + r >> 1;
if(qr <= mid) return query(a[u].ls, l, mid, ql, qr).apply(a[u].del, a[u].tag, a[u].mn);
else if(ql > mid) return query(a[u].rs, mid + 1, r, ql, qr).apply(a[u].del, a[u].tag, a[u].mn);
else return (query(a[u].ls, l, mid, ql, qr) + query(a[u].rs, mid + 1, r, ql, qr)).apply(a[u].del, a[u].tag, a[u].mn);
}
void build(int &u, int l, int r) {
u = newnode(0);
if(l == r) {
a[u].mncnt = sy[l + 1] - sy[l];
return ;
}
int mid = l + r >> 1;
build(a[u].ls, l, mid), build(a[u].rs, mid + 1, r);
up(u);
}
}ds;
int main() {
// freopen("in.txt", "r", stdin);
ios::sync_with_stdio(false), cin.tie(0);
int r, c, n, q;
cin >> r >> c >> n >> q;
vector<array<int, 4>> mat(n);
for(int i = 0; i < n; i ++) {
for(int j = 0; j < 4; j ++) cin >> mat[i][j];
if(mat[i][0] == mat[i][2] || mat[i][1] == mat[i][3]) {
i --, n --;
continue;
}
if(mat[i][0] > mat[i][2]) swap(mat[i][0], mat[i][2]);
if(mat[i][1] > mat[i][3]) swap(mat[i][1], mat[i][3]);
sx.push_back(mat[i][0]), sx.push_back(mat[i][2]);
sy.push_back(mat[i][1]), sy.push_back(mat[i][3]);
}
sx.push_back(-1), sy.push_back(-1);
sx.push_back(r + 1), sy.push_back(c + 1);
sort(sx.begin(), sx.end()), sx.erase(unique(sx.begin(), sx.end()), sx.end());
sort(sy.begin(), sy.end()), sy.erase(unique(sy.begin(), sy.end()), sy.end());
vector<vector<array<int, 3>>> upd(sx.size());
vector<int> rt(sx.size());
for(int i = 0; i < n; i ++) {
for(int j = 0; j < 4; j ++) {
if(j & 1) mat[i][j] = lower_bound(sy.begin(), sy.end(), mat[i][j]) - sy.begin();
else mat[i][j] = lower_bound(sx.begin(), sx.end(), mat[i][j]) - sx.begin();
}
upd[mat[i][0]].push_back({mat[i][1], mat[i][3] - 1, 1});
upd[mat[i][2]].push_back({mat[i][1], mat[i][3] - 1, -1});
}
ds.build(rt[0], 0, sy.size() - 2);
for(int i = 1; i < sx.size(); i ++) {
rt[i] = rt[i - 1];
ds.seta(rt[i], 0, sx[i] - sx[i - 1], 0);
for(auto u : upd[i]) ds.update(rt[i], 0, sy.size() - 2, u[0], u[1], u[2]);
}
i64 lstans = 0;
int tot = 0;
for(int i = 0; i < q; i ++) {
int x1, x2, y1, y2;
i64 v;
cin >> x1 >> y1 >> x2 >> y2 >> v;
x1 = (x1 + i128(v) * lstans) % (r + 1);
x2 = (x2 + i128(v) * lstans) % (r + 1);
y1 = (y1 + i128(v) * lstans) % (c + 1);
y2 = (y2 + i128(v) * lstans) % (c + 1);
if(x1 == x2 || y1 == y2) {
cout << (lstans = 0) << '\n';
continue;
}
if(x1 > x2) swap(x1, x2);
if(y1 > y2) swap(y1, y2);
int u1 = lower_bound(sx.begin(), sx.end(), x1) - sx.begin(), u2 = upper_bound(sx.begin(), sx.end(), x2) - sx.begin() - 1;
int v1 = lower_bound(sy.begin(), sy.end(), y1) - sy.begin(), v2 = upper_bound(sy.begin(), sy.end(), y2) - sy.begin() - 1;
auto calcy = [&] (int u1, int u2) {
auto calc = [&] (int v1, int v2) {
return ds.query(rt[u2], 0, sy.size() - 2, v1, v2).mnsum - (u1 ? ds.query(rt[u1 - 1], 0, sy.size() - 2, v1, v2).mnsum : 0);
};
if(v1 > v2) {
i64 ans = calc(v2, v2) / (sy[v1] - sy[v2]) * (y2 - y1);
return ans;
}
else {
i64 ans = (sy[v1] - y1 ? calc(v1 - 1, v1 - 1) / (sy[v1] - sy[v1 - 1]) * (sy[v1] - y1) : 0) +
(y2 - sy[v2] ? calc(v2, v2) / (sy[v2 + 1] - sy[v2]) * (y2 - sy[v2]) : 0);
if(v1 < v2) ans += calc(v1, v2 - 1);
return ans;
}
};
if(u1 > u2) {
i64 ans = calcy(u2, u2) / (sx[u1] - sx[u2]) * (x2 - x1);
cout << (lstans = 1ll * (x2 - x1) * (y2 - y1) - ans) << '\n';
}
else {
i64 ans = (sx[u1] - x1 ? calcy(u1 - 1, u1 - 1) / (sx[u1] - sx[u1 - 1]) * (sx[u1] - x1) : 0) +
(x2 - sx[u2] ? calcy(u2, u2) / (sx[u2 + 1] - sx[u2]) * (x2 - sx[u2]) : 0);
if(u1 < u2) ans += calcy(u1, u2 - 1);
cout << (lstans = 1ll * (x2 - x1) * (y2 - y1) - ans) << '\n';
}
}
return 0;
}