T1 串
背景
形貌昳丽的西克是風子国王嫡系军队的 general, 同时也兼任風子王国驻绿鸟国的外交官。
西克喜欢在蕉含流群里与其它王国的使者蕉含流, 但前段时间由于说怪话被来自绿鸟国意识形态 不完全的国王驱含逐出境。
西克非常愤怒, 想要说出一句最怪的话, 但他却忙于敢览求社的训练。
于是, 他找到了你, 无上尼特, 想让你帮助解决他的问题。
题目描述
在風子王国, 一句话由 \(n\) 个词组成, 其中恰好有 \(k\) 个词是怪的, 其它的词都不是怪的。
众所周知, 负负得正, 我们定义一句话的一个区间是怪的, 当且仅当其中含有奇数个怪词。
请构造一句符合条件的话, 使得其中怪的区间数量最多。
输入格式
从文件 string.in 中读入数据。
一行两个整数 \(n,k\) 。
输出格式
输出到文件 string.out 中。
第一行一个整数 \(ans\), 表示至多可以有的怪的区间个数。
第二行一个长度为 \(n\) 的 01 串, 表示构造方案, 若一个单词是怪的, 输出 1 , 否则输出 0 , 字符 间用空格隔开。
本题使用自定义校验器检验你的答案是否正确, 因此若有多种满足条件的方案, 你只需要输出任 意一种。
样例
输入数据 1
7 2
输出数据 1
16
0 1 0 0 0 1 0
怪的区间有 [1, 2], [1, 3], [1, 4], [1, 5], [2, 2], [2, 3], [2, 4], [2, 5], [3, 6], [3, 7], [4, 6], [4, 7], [5, 6], [5, 7], [6, 6], [6, 7] 共 16 个。
数据规模与约定
对于所有测试点:\(1≤n≤10^5,0≤k≤n\)。
每个测试点的具体限制见下表:
测试点 | \(n\) | \(k\) |
---|---|---|
1∼2 | \(≤10\) | ≤n |
3∼5 | \(≤10^3\) | 同上 |
6∼7 | \(≤10^5\) | 1 |
8 | 同上 | 2 |
9∼10 | \(≤n\) | $ \le n$ |
题解
打表题,正常看挺难看出它的规律,打表则很容易计算出来
是我不会推导
有人忘了开longlong,还没特判
大概看了一下正常思路代码我就不写了
先特判 \(k=0\) 的情况。
将数组做前缀和, 令前缀和数组中 1 的个数为 \(X,0\) 的个数为 \(Y\), 则答案为 \(X \times Y\), 由于\(X+Y=n+1\), 所以我们只需要让 \(X,Y\) 尽量接近, 一种简单的做法是先在最前方放 \(k−1\) 个 1 , 再在后面的位置中选择最优 的位置放一个 1 , 可以发现, 这样构造一定能够做到 \(X \times Y\) 取到最大, 时间复杂度 \(\mathcal O(n)\),
#include<bits/stdc++.h>
using namespace std;
int n,k,a[100010];
long long ans;
int main(){
freopen("string.in","r",stdin);
freopen("string.out","w",stdout);
scanf("%d%d",&n,&k);
if(k==0){
puts("0");
for(int i = 1;i<=n;i++)
printf("0 ");
return 0;
}
ans = (long long)((n/2)+1)*(long long)(n/2);
if(n%2==1) ans+=(long long)(n/2)+1;
printf("%lld\n",ans);
for(int i = n;i>=n-k+2;i--) a[i] = 1;
a[(n-k)/2+1] = 1;
for(int i = 1;i<=n;i++)
printf("%d ",a[i]);
return 0;
}
背景
吉娜是一名艺术家, 一名表演艺术家 (performance artist)。
此时正值風子王国建国 114514 周年, 風子国王抵德请来艺术家吉娜设计游行的道路。
吉娜非常重占视这份工作, 但却在喝水的时候被巡逻的抵德训占斥工作不认真, 于是剥占夺了吉 娜的设计权利, 将吉娜贬含为了负责计算道路的信息的计算机。
吉娜心想: “为什么设计的时候不能喝水? ?? 我听歌都可以设计好。”
但终是敢怒占不敢言, 不幸的是, 计算量实在太大, 吉娜怕黑, 必须赶在天黑占之前做完工作。 于是他请来了你, 伟大尼特, 帮助它解决这个问题。
题目描述
给定一个长度为 n 的颜色序列 c 。
再给出 m 个区间, 第 i 个区间为 \([l_i,r_i]\) 保证任何两个区间都是不相交或包含的关系。
在接下来的 q 个单位时间内, 第 \(i\) 个时间会给定 \(x,y\), 表示将 \(c_x\) 变为 \(y\) 。
请对于每一个区间求出, 最早的其中所有颜色都互不相同的时间。
输入格式
从文件 artist.in 中读入数据。
第一行三个正整数 \(n,m,q\) 。
接下来一行 \(n\) 个整数, 第 \(i\) 个数表示第 \(i\) 个点的初始颜色 \(c_i\)。
接下来 \(m\) 行, 每行两个整数 $l_i,r_i $。
接下来 \(q\) 行, 每行两个整数 \(x,y\), 表示一次修改。
输出格式
输出到文件 artist.out 中。
令 \(L_i\) 表示第 \(i\) 个区间之中最早的所有颜色互不相同的时间, 若在修改前就已经满足条件, 则 \(L_i=0\), 若不存在这样的时间, 则令 \(L_i = m+i\) 。
请输出 \(⨁_{i=1}^mL_i\), 其中 \(⨁\) 表示二进制下的按位异或。
样例
输入数据 1
6 6 5
1 2 1 2 1 2
1 6
5 5
4 5
3 5
2 5
1 5
5 2
4 3
2 1
3 4
1 5
输出数据 1
4
【样例解释 1】
\(L_i\) 依次为 7,0,0,2,4,5 。
数据规模与约定
对于所有数据, 满足 \(1≤n,m,q≤5×10^5,1≤l_i≤r_i≤n,1≤c_i,y≤n\), 保证任何两个区间都是 不相交或包含的关系,保证不存在两个完全相同的区间。
题解
发现所有区间不相交也不包含, 可以看作一个树形的关系, 一个区间的父亲必须在这个区间之后满足要求, 同时, 所有的叶子节点的区间互不相交, 相当于每个点只会在当前的一个区间中, 每次修改之后查询这个区 间是否合法即可。
查询一个区间是否合法有两种方式:
-
建出树, 相当于一个单点修改, 子树数颜色, 使用 dfsdfs 序, set, 树状数组可以做到 \(\mathcal O(logn)\) 。
-
在原数轴上维护 \(lst_i\) 表示 \(i\) 之前第一个颜色与 \(i\) 相同的点, 则一个区间内部颜色互不相同等价于 \(\min \{ lst_i,l≤i≤r \}\), 使用 set 和线段树维护可以做到 \(\mathcal O(logn)\)。
时间复杂度 \(\mathcal O(n+(m+q)logn)\) 。
#include<bits/stdc++.h>
#define N 500010
#define mid ((l+r)>>1)
#define lc (p<<1)
#define rc ((p<<1)|1)
using namespace std;
struct node{
int x,y,id;
bool operator<(const node &a)const{
return x==a.x?y>a.y:x<a.x;
}
}stk[N],p[N];
set<node>s;
set<node>::iterator it1;
set<int>st[N];
set<int>::iterator it;
int n,m,q,cnt,tim,X,Y,tp,lf[N],rg[N],rd[N],ans[N],c[N],h[N],ne[N],t[N<<2],lst[N],fa[N],pos[N],pre[N];
void add(int p,int l,int r){
if(l==r){
t[p] = Y;
return ;
}
if(X<=mid) add(lc,l,mid);
else add(rc,mid+1,r);
t[p] = max(t[lc],t[rc]);
}
int ask(int p,int l,int r,int ql,int qr){
if(ql<=l&&qr>=r) return t[p];
int res = 0;
if(ql<=mid) res = max(res,ask(lc,l,mid,ql,qr));
if(qr>mid) res = max(res,ask(rc,mid+1,r,ql,qr));
return res;
}
void build(int p,int l,int r){
if(l==r){
t[p] = lst[l];
return ;
}
build(lc,l,mid);
build(rc,mid+1,r);
t[p] = max(t[lc],t[rc]);
}
void change(int x,int y){
if(ne[x]){
X = ne[x];
Y = lst[x];
add(1,1,n);
}
ne[lst[x]] = ne[x];
lst[ne[x]] = lst[x];
st[c[x]].erase(x);
c[x] = y;
int p = lst[x];
it = st[y].upper_bound(x);
lst[x] = ne[x] = 0;
if(it!=st[y].end()){
X = *it;
ne[x] = X;
Y = x;
add(1,1,n);
}
if(it!=st[y].begin()){
it--;
lst[x] = *it;
}
st[y].insert(x);
lst[ne[x]] = ne[lst[x]] = x;
X = x;
Y = lst[x];
if(p^Y) add(1,1,n);
}
void check(int x){
if(ask(1,1,n,lf[x],rg[x])<lf[x]){
s.erase((node){lf[x],rg[x],x});
ans[x] = tim;
if(fa[x]&&(!(--rd[fa[x]]))){
rd[fa[x]] = -1;
s.insert(p[pos[fa[x]]]);
check(fa[x]);
}
}
}
int main(){
freopen("artist.in","r",stdin);
freopen("artist.out","w",stdout);
scanf("%d%d%d",&n,&m,&q);
for(int i = 1;i<=n;i++)
scanf("%d",&c[i]);
for(int i = 1;i<=m;i++){
lst[i] = pre[c[i]];
ne[pre[c[i]]] = i;
pre[c[i]] = i;
st[c[i]].insert(i);
}
build(1,1,n);
for(int i = 1;i<=m;i++){
scanf("%d%d",&p[i].x,&p[i].y) ;
lf[i] = p[i].x;rg[i] = p[i].y;
ans[i] = m+i;
p[i].id = i;
}
sort(p+1,p+m+1);
for(int i = 1;i<=m;i++){
if(p[i].x==p[i].y||ask(1,1,n,p[i].x,p[i].y)<p[i].x){
ans[p[i].id] = 0;
rd[p[i].id] = -1;
continue;
}
pos[p[i].id] = i;
while(tp&&stk[tp].y<p[i].x) tp--;
fa[p[i].id] = stk[tp].id;
stk[++tp] = p[i];
rd[fa[p[i].id]]++;
}
for(int i = 1;i<=m;i++){
if(!rd[p[i].id])
s.insert(p[i]);
}
for(int i = 1;i<=q;i++){
int x,y;
scanf("%d%d",&x,&y);
tim = i;
change(x,y);
it1 = s.upper_bound((node){x,0,0});
if(it1!=s.begin()){
it1--;
check((*it1).id);
}
}
int res = 0;
for(int i = 1;i<=m;i++)
res^=ans[i];
printf("%d",res);
return 0;
}
T3 黑白树(tree)
背景
一天, 風子国王抵德带着助手尼特以及西可和西克来到一片 dark 含森林探险, 在这里, 它们发 现了 \(n\) 个阿玮。
与此同时, 杰哥带着彬概也正好发现了这些阿玮。
与此同时, 抵德也发现了杰哥带着彬彬也正好发现了这些阿玮。
抵德说: “如果这些阿玮给你的话, 那么它们就不是我的了”。
杰哥说: “如果这些阿玮给你的话, 那么它们就不是我的了”。
两边吵得不可开蕉♂,这时,尼特发现,这些阿玮有些非常逊,有一些非常勇♂,于是经过调解, 抵德带走了所有逊的阿玮, 杰哥带走了所有勇含的阿玮。
同时, 尼特发现这 \(n\) 个阿玮之间仿佛产生了 \(n−1\) 条联系, 构成了一棵树的关系。
题目描述
给定一棵 \(n\) 个点的树, 每一个结点都可以是黑色或白色, 每一条边的长度都为 1 。
定义两个点的距离为两个点最短路径上边的条数, 定义一棵树的价值, 为同色点距离的最大值。 请求出在所有情况下, 树的价值之和, 对 \(10^9+7\) 取模。
输入格式
从文件 tree.in 中读入数据。
第一行一个正整数 \(n\) 。
接下来 \(n−1\) 行, 每行两个数 \(x,y\), 表示树中的一条边。
输出格式
输出到文件 tree.out 中。
输出一行一个数, 表示你的答案, 对 \(10^9+7\) 取模。
样例
输入数据 1
2
1 2
输出数据 1
2
【样例解释 1】
若两个点颜色相同,同色点距离最大值为 1。
若两个点颜色不同,同色点距离最大值为 0。
输入数据 2
6
1 2
2 3
3 4
4 5
3 6
输出数据 2
224
题解
#include<bits/stdc++.h>
#define N 1000010
#define mod 1000000007
using namespace std;
struct edge{
int v,ne;
}e[N<<1];
int n,s,cnt,ans,pos,sum,h[N],dis[N],c[N],dis1[N],c1[N];
bool vis[N];
void add(int u,int v){
e[++cnt].v = v;
e[cnt].ne = h[u];
h[u] = cnt;
}
int ksm(int x,int y){
int ans = 1;
while(y){
if(y&1) ans = 1ll*ans*x%mod;
x = 1ll*x*x%mod;
y>>=1;
}
return ans;
}
void dfs(int u,int fa,int x){
dis[u] = x;
if(dis[u]>dis[pos]) pos = u;
for(int i = h[u];i;i = e[i].ne){
int v = e[i].v;
if(v!=fa) dfs(v,u,x+1);
}
}
int main(){
freopen("tree.in","r",stdin);
freopen("tree.out","w",stdout);
scanf("%lld",&n);
for(int i = 1;i<n;i++){
int u,v;
scanf("%d%d",&u,&v);
add(u,v);add(v,u);
}
dfs(1,1,0);
int x = pos;
pos = 0;
dfs(x,x,0);
for(int i = 1;i<=n;i++){
if(dis[i]==dis[pos])
sum++;
c[dis[i]]++;
}
for(int i = 1;i<=n;i++){
dis1[i] = dis[i];
c1[i] = c[i];
}
x = pos;
dfs(x,x,0);
memset(c,0,sizeof(c));
for(int i = 1;i<=n;i++){
if(dis[i]==dis[pos])
sum++;
c[dis[i]]++;
}
for(int i = 1;i<=n;i++)
vis[min(dis[i],dis1[i])] = true;
int mx = dis[pos];
sum = ksm(2,n);
s = n+1;
for(int i = mx;~i;i--){
if(vis[i]){
ans = (ans+1ll*sum*i%mod)%mod;
printf("%d",ans);
return 0;
}
s-=c[i];
s-=c1[i];
int tmp = ksm(2,s);
ans = (ans+1ll*i*(sum-tmp+mod)%mod)%mod;
sum = tmp;
}
return 0;
}
T4敢览求(rugby)
题目
题解
写不动了容我偷个懒
这道题根本不是给人写的吧
#include<bits/stdc++.h>
#define N 200010
using namespace std;
struct node{
int x,y;
bool operator <(const node A)const{
return x==A.x?y<A.y:x<A.x;
}
};
int n,K,ls[N],rs[N],a[N],b[N],f[N],cc,tot;
multiset<node>st[N];
multiset<node>::iterator it,it1,it2,it3,it4;
void find(multiset<node>&A,int x){
it1 = A.upper_bound((node){x+1,-1});
}
bool ck(multiset<node>&A,multiset<node>&B){
cc = 0;
for(it = B.begin();it!=B.end();it++){
find(A,(*it).x);
if(it1!=A.begin()){
it1--;
if((*it1).y>=(*it).x) return 1;
it1++;
}
if(it1!=A.end()&&(*it1).x<=(*it).y)return 1;
tot++;
}
return 0;
}
void cg1(multiset<node>&A,multiset<node>&B){
it2 = A.begin();
cc = 0;
for(it = B.begin();it!=B.end();it++){
find(A,(*it).x);
while(it2!=A.end()&&(*it2).y<(*it).x)it3=it2,++it2,A.erase(it3);
if(it1!=A.begin()){
it1--;
int xx = -1;
if((*it1).y>=(*it).x){
xx = min((*it).y,(*it1).y);
A.insert((node){(*it).x,xx});
A.erase(it1);
}
if(~xx&&(*it1).y!=xx) A.insert((node){xx+1,(*it1).y});
}
find(A,(*it).y);
if(it1!=A.begin()){
it1--;
int xx = -1;
if((*it1).x<=(*it).y){
xx = min((*it).y,(*it1).y);
A.insert((node){(*it).x,xx});
}
if(~xx&&(*it1).y!=xx) A.insert((node){xx+1,(*it1).y});
A.erase(it1);
}
it2 = A.upper_bound((node){(*it).y+1,-1});
tot++;
}
while(it2!=A.end()){
it3 = it2;
it2++;
A.erase(it3);
}
}
void cg2(multiset<node>&A,multiset<node>&B){
for(it = B.begin();it!=B.end();it++){
int l = (*it).x,r = (*it).y;
find(A,l);
if(it1!=A.begin()){
it1--;
l = max(l,(*it1).y+1);
it1++;
}
while(it1!=A.end()&&(*it1).y<=r){
it2 = it1;
it1++;
A.erase(it2);
}
if(it1!=A.end()) r = min(r,(*it1).x-1);
if(l<=r) A.insert((node){l,r});
tot++;
}
}
void dfs(int x){
if(!ls[x]) swap(ls[x],rs[x]);
if(ls[x]) dfs(ls[x]);
if(rs[x]) dfs(rs[x]);
if(a[x]>=b[x]){
st[x].insert((node){0,K-a[x]-1});
if(b[x]) st[x].insert((node){K-b[x],K-1});
}else st[x].insert((node){K-b[x],K-a[x]-1});
if(!ls[x]) return;
if(!rs[x]){
if(ck(st[ls[x]],st[x])){
cg1(st[ls[x]],st[x]);
f[x] = f[ls[x]];
}else{
cg2(st[ls[x]],st[x]);
f[x] = f[ls[x]]+1;
}
st[x].swap(st[ls[x]]);
return ;
}
multiset<node>tmp1,tmp2;
if(st[ls[x]].size()<st[rs[x]].size()) swap(ls[x],rs[x]);
if(ck(st[x],st[rs[x]])){
tmp1 = st[rs[x]];
cg1(tmp1,st[x]);
if(ck(tmp1,st[ls[x]])){
cg1(st[ls[x]],tmp1);
st[x].swap(st[ls[x]]);
f[x] = f[ls[x]]+f[rs[x]];
}else{
tmp2 = st[rs[x]];
cg2(tmp2,st[x]);
cg1(st[ls[x]],tmp2);
cg2(st[ls[x]],tmp1);
st[x].swap(st[ls[x]]);
f[x] = f[ls[x]]+f[rs[x]]+1;
}
}else if(ck(st[ls[x]],st[x])||ck(st[ls[x]],st[rs[x]])){
cg2(st[x],st[rs[x]]);
cg1(st[ls[x]],st[x]);
swap(st[x],st[ls[x]]);
f[x] = f[ls[x]]+f[rs[x]]+1;
}else{
cg2(st[ls[x]],st[x]);
cg2(st[ls[x]],st[rs[x]]);
st[x].swap(st[ls[x]]);
f[x] = f[ls[x]]+f[rs[x]]+2;
}
}
int main(){
freopen("rugby.in","r",stdin);
freopen("rugby.out","w",stdout);
scanf("%d%d",&n,&K);
for(int i = 1;i<=n;i++)
scanf("%d%d%d%d",&a[i],&b[i],&ls[i],&rs[i]);
dfs(1);
if((*st[1].begin()).x>0) f[1]++;
printf("%d",f[1]);
return 0;
}
最后一道绝对有点问题,烦请各位指正
标签:校内,int,ne,st,lst,区间,230715,it1 From: https://www.cnblogs.com/cztq/p/17561394.html