题目分享H 二代目
题意:有m个限制,每个限制l1,r1,l2,r2四个数,限制了一个长度为n的数第l1到r1位要与第l2到r2相同,保证r1-l1=r2-l2,求在限制下一共有多少种数
分析:
暴力的话肯定是从l1-r1扫一遍用并查集,但显然时间和空间都是不允许的
但再一想,这是不是相当于区间并?操作
看到区间的东西,我直接就往线段树去想了
#include<cstdio>
#include<map>
#include<algorithm>
using namespace std; #define pii pair<int,int>
#define ll long long const int mod=1e9+; map<pii,pii> fa;
int n; pii find(pii x)
{
while(x!=fa[x]) x=fa[x];
return x;
} pii ya(pii x)
{
pii fax=find(x),nowfa;
while(x!=fax)
{
nowfa=fa[x];
fa[x]=fax;
x=nowfa;
}
return fax;
} void bing(pii x,pii y)
{
pii fax=ya(x),fay=ya(y);
fa[fay]=fax;
} void down(int l,int r)
{
int mid=l+r>>;
int p=ya(make_pair(l,r)).first-l;
bing(make_pair(l,mid),make_pair(l+p,mid+p));
bing(make_pair(mid+,r),make_pair(mid++p,r+p));
} void dfs(int l,int r,int left,int right,int p)
{
if(l>=left&&r<=right)
{
bing(make_pair(l,r),make_pair(l+p,r+p));
return;
}
down(l,r);
int mid=l+r>>;
if(left<=mid) dfs(l,mid,left,right,p);
if(mid>right) dfs(mid+,r,left,right,p);
} void mem(int l,int r)
{
fa[make_pair(l,r)]=make_pair(l,r);
if(l==r) return;
int mid=l+r>>;
mem(l,mid);mem(mid+,r);
} void get_ans(int l,int r)
{
if(l==r) return;
down(l,r);
int mid=l+r>>;
get_ans(l,mid);get_ans(mid+,r);
} ll pow(int x,int y)
{
ll now=(ll)x,ans=1ll;
while(y)
{
if(y&) ans*=now,ans%=(ll)mod;
y>>=;now*=now,now%=(ll)mod;
}
return ans;
} int main()
{
int m,l1,r1,l2,r2;
scanf("%d%d",&n,&m);
mem(,n);
while(m--)
{
scanf("%d%d%d%d",&l1,&r1,&l2,&r2);
dfs(,n,l1,r1,l2-l1);
}
get_ans(,n);
int ans=-;
for(int i=;i<=n;i++) if(fa[make_pair(i,i)]==make_pair(i,i)) ans++;
printf("%d",(int)(pow(,ans)*%mod));
return ;
}
然鹅,这个pair可能有点不好开,导致全员MLE
不过处理区间的东西,ST表也是有地位的
于是就能往ST表那里去想
首先ST表传统艺能肯定是f[x][k]表示x到x+(1<<k)左闭右开怎么怎么样,
那么这里就应该表示x到x+(1<<k)左闭右开的父亲是谁(因为要搞并查集)
而这里的父亲应该对应另一个y到y+(1<<k)的区间,因为我们的k是已知的,所以其实f[x][k]只需要记录这个y即可,也就是对应区间的左端点
而这m组将两个区间并起来的操作时,也应该像lca向上跳一样,从maxlg往下慢慢找符合的k,然后再讲x跳到其对应的x+(1<<k)位置上
这里有一点值得注意,其实我们这里也可以按照平日ST表那样只将l到l+(1<<k)与 r-(1<<k)+1,r+1这两个区间与对应的区间合并(这里k应该是小于等于r-l的最大的k)
但我认为这样不如像lca那样快,如果有和我意见不相同的可以讨论一波
但你肯定马上就会想,这只合并两个,而lca合并很多个区间,但这些合并其实都要下放的
为了方便统计,最后要干的是将所有的结果下传,达到每个单个的位置对应一个位置的效果,
这又类似线段树了,下传标记
这应该很好理解,ya()后得到的是f[x][y]所对应的根节点区间的左端点,这里bing传的三个参数分别为l1,l2,k,也就是把l1到l1+(1<<k)左闭右开与l2到l2+(1<<k)左闭右开合并
最后得到每个单个位置对应的位置,只需要数数有多少个f[x][0]=x即可(f[x][0]=x表示这个x是这个并查集的根节点)
对了,还有一个小问题,你统计出来的这个值是指能自由取数的个数,但显然这其中一定有一个位置与首位相关,这个位置只能取1-9,别的位置则能取0-9
所以最后结果应该是9*10^(count-1)
代码:
#include<cstdio>
#include<map>
#include<algorithm>
using namespace std; #define ll long long const int mod=1e9+;
const int maxn=1e5+;
const int maxlg=2e1+; int fa[maxn][maxlg];
int n; int find(int x,int y)
{
while(x!=fa[x][y]) x=fa[x][y];
return x;
} int ya(int x,int y)
{
int fax=find(x,y),nowfa;
while(x!=fax)
{
nowfa=fa[x][y];
fa[x][y]=fax;
x=nowfa;
}
return fax;
} void bing(int x1,int x2,int y)
{
int fax=ya(x1,y),fay=ya(x2,y);
fa[fay][y]=fax;
} void down(int x,int y)
{
int nowx=ya(x,y);
bing(x,nowx,y-);
bing(x+(<<y-),nowx+(<<y-),y-);
} void get_ans()
{
for(int i=maxlg-;i;i--) for(int j=;j<=n;j++) if(j+(<<i)<=n+) down(j,i);
} void mem()
{
for(int i=;i<maxlg;i++) for(int j=;j<=n;j++) if(j+(<<i)<=n+) fa[j][i]=j;
} ll pow(int x,int y)
{
ll now=(ll)x,ans=1ll;
while(y)
{
if(y&) ans*=now,ans%=(ll)mod;
y>>=;now*=now,now%=(ll)mod;
}
return ans;
} int main()
{
int m,l1,r1,l2,r2;
scanf("%d%d",&n,&m);
mem();
while(m--)
{
scanf("%d%d%d%d",&l1,&r1,&l2,&r2);
int now=r1-l1+;
for(int i=maxlg-;i>=;i--)
{
if((<<i)<=now)
{
bing(l1,l2,i);now-=(<<i);
l1+=(<<i);l2+=(<<i);
}
}
}
get_ans();
int ans=-;
for(int i=;i<=n;i++) if(fa[i][]==i) ans++;
printf("%d",(int)(pow(,ans)*%mod));
return ;
}
题目分享H 二代目的更多相关文章
- 题目分享E 二代目
题意:一棵点数为n的树,每个节点有点权,要求在树中中找到一个最小的x,使得存在一个点满足max(该点点权,该点相邻的点的点权+1,其他点的点权+2)=x 分析:首先要能把题目转化为上述题意 首先题目让 ...
- 题目分享D 二代目
题意:给定一个T条边的无向图,求S到E恰好经过N条边的最短路径 T≤100 N≤1000000 分析:(据说好像假期学长讲过) 首先很容易想到的是dp[i][j][k]表示从i到j经过k条边的最短路径 ...
- 题目分享C 二代目
题意:一个数列是由 1 1 2 1 2 3 1 2 3 4 1 2 3 4 5 1 2 3 4 5 6.....组成,也就是1-1,1-2,1-3......并且如果遇到多位数也要拆成数字比如1-10 ...
- 题目分享G 二代目
题意:有n组数,每组包含两个数,问在每组只能取一个的前提下能组成的最长的从1开始的连续自然数有几个? 分析:刚学了差分约束系统,很容易往转换成图的方向去想 将他读入的这n组数当成边读入 很容易会得到一 ...
- 题目分享F 二代目
题意:T个点R种双向边,P种单向边,求点S到每个点的最短距离 分析:(这再看不出来是spfa就该**了) 首先,这题能否用spfa就看他是否有负环呗,显然,双向边的权值非负,单向边还有个啥政策,总之显 ...
- 题目分享V
题意:现在两个人做游戏,每个人刚开始都是数字1,谁赢了就能乘以k^2,输的乘以k(k可以是任意整数,每次不一定相同)现在给你最终这两个人的得分,让你判断是否有这个可能,有可能的话Yes,否则No. 分 ...
- 2019年腾讯PHP程序员面试题目分享
有需要学习交流的友人请加入交流群的咱们一起,有问题一起交流,一起进步!前提是你是学技术的.感谢阅读! 点此加入该群jq.qq.com 1. php 的垃圾回收机制 PHP 可以自动进行内存管理,清除 ...
- 20190924-LeetCode解数独题目分享
解决数独 题目描述 编写一个程序,通过已填充的空格来解决数独问题. 一个数独的解法需遵循如下规则: 数字 1-9 在每一行只能出现一次. 数字 1-9 在每一列只能出现一次. 数字 1-9 在每一个以 ...
- 题目分享X
题意:一张票有n位数,如果这张票的前一半数字的和等于后一半数字的和(n一定是偶数),就称这张票为快乐票.有些数被擦除了,标记为’?’(’?‘的个数也是偶数),现在Monocarp 和 Bicarp 进 ...
随机推荐
- 第一章 AT&T
1.一个公司(企业)越庞大,就越危险:越复杂,就越濒临坍塌:快速发展的同时,也埋下了隐患. 2.再庞大的企业也不可能永久站立,下个十年谁也说不准谁会在浪潮之巅. 3.一个人能走多远,往往取决于他能看多 ...
- Windows Server 2016 Storage Replication
Storage Replication是Windows Server 2016中新增的一项功能,它是利用windows server自带的块存储复制技术 首先,我们简答粗暴的交代一下部署需求: 1.该 ...
- java消除 list重复值及交集,并集,差集
消除 list重复值 Java代码 public void removeDuplicate(List list) { HashSet h = new HashSet(list); list.clea ...
- split(resource,limit) 中limit 的含义
limit 参数控制模式应用的次数,因此影响结果数组的长度.如果该限制 n 大于 0,则模式将被最多应用 n - 1 次,数组的长度将不会大于 n,而且数组的最后项将包含超出最后匹配的定界符的所有输入 ...
- 常用Linux命令的基本使用
01.常用Linux命令的基本使用 序号 命令 对应英文 作用 01 ls list 查看当前文件夹下的内容 02 pwd print work directory 查看当前所在文件夹 03 cd [ ...
- commonJS、AMD和CMD之间的区别
JS中的模块规范(CommonJS,AMD,CMD),如果你听过js模块化这个东西,那么你就应该听过或CommonJS或AMD甚至是CMD这些规范咯,我也听过,但之前也真的是听听而已. 现在就看看吧, ...
- Win32 Disk Imager刻录过的U盘恢复容量的方法
近日遇到一个问题,使用Win32 Disk Imager刻录过的U盘,想恢复使用,但无法正常使用. 按WIN+R键调出Win10运行框,输入diskmgmt.msc,打开磁盘管理工具. 看到U盘的状况 ...
- C. 无穷的小数
单点时限: 1.0 sec 内存限制: 512 MB 在十进制下,我们能够很轻易地判断一个小数的位数是有穷的或无穷的,但是把这个小数用二进制表示出的情况下其有穷性和无穷性就会发生改变,比如 十进制下的 ...
- django.template.exceptions.TemplateDoesNotExist: login.html报错
前言 在某一次按以前的步骤使用Django “django.template.exceptions.TemplateDoesNotExist: login.html”错误,在以为是html文件出 ...
- [git] github上传项目(使用git)、删除项目、添加协作者
来源:http://www.cnblogs.com/sakurayeah/p/5800424.html (怕链接失败,所以直接就就复制过来啦,感谢作者) 一.注册github账号 github网址ht ...