加权并查集:
// http://poj.org/problem?id=1182
#include
struct node
{
int p;
int r;
}a[50005];
int find(int x)
{
if(x==a[x].p) return x;
int t=a[x].p;
a[x].p=find(t);
a[x].r=(a[x].r+a[t].r)%3;
return a[x].p;
}
int main()
{
int N,k;
scanf("%d%d",&N,&k);
int i,j,d,x,y,ans=0;
for(i=1;i<=N;i++)
{
a[i].p=i;
a[i].r=0;
}
for(i=0;iN||y>N) ans++;
else
{
if(d==2&&x==y) ans++;
else
{
int c=find(x);
int b=find(y);
if(c!=b)
{
a[b].p=c;
a[b].r=(3+d-1+a[x].r-a[y].r)%3;
}
else
{
if(d==2&&((3-a[x].r+a[y].r)%3!=d-1)) ans++;
if(d==1&&a[x].r!=a[y].r) ans++;
}
}
}
}
printf("%d\n",ans);
return 0;
}
线段树(单点更新,区间求和)
//http://acm.hdu.edu.cn/showproblem.php?pid=1754
#include
#include
#include
using namespace std;
const int N=200000+5;
struct Node
{
int left,right;
int value;
};
Node tree[N<<2];
int father[N<<2];
void BuiltTree(int l,int r,int i)
{
tree[i].value=0;
tree[i].right=r;
tree[i].left=l;
if(l==r)
{
father[l]=i;
// printf("f %d %d %d\n",father[l],i,l);
return ;
}
BuiltTree(l,(int)(floor)(l+r)/2,i<<1);
BuiltTree((int)(floor)(l+r)/2+1,r,(i<<1)+1);
}
void Update(int i)
{
i>>=1;
if(i==0) return ;
tree[i].value=max(tree[i<<1].value,tree[(i<<1)+1].value);
// printf("%d %d %d %d\n",i,tree[i].value,tree[i<<1].value,tree[(i<<1)+1].value);
Update(i);
}
int ans;
void query(int l,int r,int i)
{
if(l==tree[i].left && r==tree[i].right)
{
ans=max(tree[i].value,ans);
return ;
}
i<<=1;
if(l<=tree[i].right)
{
if(r<=tree[i].right)
query(l,r,i);
else query(l,tree[i].right,i);
}
i++;
if(r>=tree[i].left)
{
if(l>=tree[i].left) query(l,r,i);
else query(tree[i].left,r,i);
}
}
int main()
{
int n,m;
while(~scanf("%d%d",&n,&m))
{
BuiltTree(1,n,1);
int i=1;
while(i<=n)
{
scanf("%d",&tree[father[i]].value);
Update(father[i]);
// printf("%d \n",tree[father[i]].value);
i++;
}
while(m--)
{
char a[2];
int v;
scanf("%s%d%d",a,&i,&v);//printf("%c %d\n",a[0],father[i]);
if(a[0]=='U')
{
// printf("v%d %d\n",father[i],tree[father[i]].value);
tree[father[i]].value=v;
// printf("v%d %d\n",father[i],tree[father[i]].value);
Update(father[i]);
}
else
{
ans=0;
query(i,v,1);
printf("%d\n",ans);
}
}
}
return 0;
}
区间线段树(区间修改,区间求和)
// http://poj.org/problem?id=3468
#include
#define ll long long
const int N=100000;
struct Node
{
int l,r;
int mid()
{
return (l+r)>>1;
}
}tree[N<<2];
ll sum[N<<2],add[N<<2];
void pushup(int i){sum[i]=sum[i<<1]+sum[i<<1|1];}
void pushdown(int i,int m)
{
if(add[i])
{
add[i<<1]+=add[i];
add[i<<1|1]+=add[i];
sum[i<<1]+=add[i]*(m-(m>>1));
sum[i<<1|1]+=add[i]*(m>>1);
add[i]=0;
}
}
void buildtree(int l,int r,int i)
{
tree[i].l=l;
tree[i].r=r;
add[i]=0;
if(l==r)
{
scanf("%lld",&sum[i]);
// printf("%d %d %d\n",i,sum[i],l);
return ;
}
int m=tree[i].mid();
buildtree(l,m,i<<1);
buildtree(m+1,r,i<<1|1);
pushup(i);
}
void update(int l,int r,int i,ll w)
{
if(tree[i].l==l&&tree[i].r==r)
{
sum[i]+=(ll)w*(tree[i].r-tree[i].l+1);
add[i]+=w;
return ;
}
if(tree[i].l==tree[i].r) return ;
pushdown(i,tree[i].r+1-tree[i].l);
int m=tree[i].mid();
if(l>m) update(l,r,i<<1|1,w);
else if(r<=m) update(l,r,i<<1,w);
else
{
update(l,m,i<<1,w);
update(m+1,r,i<<1|1,w);
}
pushup(i);
}
ll ans;
ll query(int l,int r,int i)
{
if(tree[i].l==l&&tree[i].r==r)
{
return sum[i]+ans;
}
pushdown(i,tree[i].r+1-tree[i].l);
int m=tree[i].mid();
if(l>m) ans=query(l,r,i<<1|1);
else if(r<=m) ans=query(l,r,i<<1);
else
{
ans=query(l,m,i<<1);
ans=query(m+1,r,i<<1|1);
}
return ans;
}
int main()
{
int n,q,l,r,w;
scanf("%d%d",&n,&q);
buildtree(1,n,1);
while(q--)
{
char a[2];
getchar();
scanf("%s",a);
if(a[0]=='Q')
{
scanf("%d%d",&l,&r);
ans=0;
printf("%lld\n",query(l,r,1));
}
else
{
scanf("%d%d%d",&l,&r,&w);
update(l,r,1,w);
}
}
return 0;
}
STL
一.Algorithm
给定一个vector容器:vector nums={8,7,5,4,2,9,6,1,3,0};
find:find(nums.begin(),nums.end(),4);
find the number 4 ,return the iterator of the number。
返回第一次出现4的位置的迭代器(可以理解为指针,但不同。)
想要得到4所在位置的下标,可以写作
find(nums.begin(),nums.end(),4)-nums.begin();
注:若未找到则返回nums.end()
swap:swap(nums[0],nums[2]);
交换nums中下标为0和下标为2的元素。
for_each:for_each(nums.begin(),nums.end(),[](int n){cout< #include #include
using namespace std;
int main()
{
vectornums={8,7,5,4,2,9,6,1,3,0}; cout<n2;}); for_each(nums.begin(),nums.end(),[](int n){cout<::iterator it; it=adjacent_find(nums.begin(),nums.end() );
all_of C++11 检测在给定范围中是否所有元素都满足给定的条件bool flag= std::all_of(nums.begin(), nums.end(),[](int i);
any_of C++11 检测在给定范围中是否存在元素满足给定条件
count 返回值等价于给定值的元素的个数
count_if 返回值满足给定条件的元素的个数
equal 返回两个范围是否相等
find 返回第一个值等价于给定值的元素
find_end 查找范围A中与范围B等价的子范围最后出现的位置
find_first_of 查找范围A中第一个与范围B中任一元素等价的元素的位置
find_if 返回第一个值满足给定条件的元素
find_if_notC++11 返回第一个值不满足给定条件的元素
for_each 对范围中的每个元素调用指定函数
mismatch 返回两个范围中第一个元素不等价的位置
none_ofC++11 检测在给定范围中是否不存在元素满足给定的条件
search 在范围A中查找第一个与范围B等价的子范围的位置
search_n 在给定范围中查找第一个连续n个元素都等价于给定值的子范围的位置
修改内容的序列操作:
copy 将一个范围中的元素拷贝到新的位置处
copy_backward 将一个范围中的元素按逆序拷贝到新的位置处
copy_ifC++11 将一个范围中满足给定条件的元素拷贝到新的位置处
copy_nC++11 拷贝 n 个元素到新的位置处
fill 将一个范围的元素赋值为给定值
fill_n 将某个位置开始的 n 个元素赋值为给定值
generate 将一个函数的执行结果保存到指定范围的元素中,用于批量赋值范围中的元素
generate_n 将一个函数的执行结果保存到指定位置开始的 n 个元素中
iter_swap 交换两个迭代器(Iterator)指向的元素
moveC++11 将一个范围中的元素移动到新的位置处
move_backwardC++11 将一个范围中的元素按逆序移动到新的位置处
random_shuffle 随机打乱指定范围中的元素的位置
remove 将一个范围中值等价于给定值的元素删除
remove_if 将一个范围中值满足给定条件的元素删除
remove_copy 拷贝一个范围的元素,将其中值等价于给定值的元素删除
remove_copy_if 拷贝一个范围的元素,将其中值满足给定条件的元素删除
replace 将一个范围中值等价于给定值的元素赋值为新的值
replace_copy 拷贝一个范围的元素,将其中值等价于给定值的元素赋值为新的值
replace_copy_if 拷贝一个范围的元素,将其中值满足给定条件的元素赋值为新的值
replace_if 将一个范围中值满足给定条件的元素赋值为新的值
reverse 反转排序指定范围中的元素
reverse_copy 拷贝指定范围的反转排序结果
rotate 循环移动指定范围中的元素
rotate_copy 拷贝指定范围的循环移动结果
shuffleC++11 用指定的随机数引擎随机打乱指定范围中的元素的位置
swap 交换两个对象的值
swap_ranges 交换两个范围的元素
transform 对指定范围中的每个元素调用某个函数以改变元素的值
unique 删除指定范围中的所有连续重复元素,仅仅留下每组等值元素中的第一个元素。
unique_copy 拷贝指定范围的唯一化(参考上述的 unique)结果
划分操作:
is_partitionedC++11 检测某个范围是否按指定谓词(Predicate)划分过
partition 将某个范围划分为两组
partition_copyC++11 拷贝指定范围的划分结果
partition_pointC++11 返回被划分范围的划分点
stable_partition 稳定划分,两组元素各维持相对顺序
排序操作:
is_sortedC++11 检测指定范围是否已排序
is_sorted_untilC++11 返回最大已排序子范围
nth_element 部份排序指定范围中的元素,使得范围按给定位置处的元素划分
partial_sort 部份排序
partial_sort_copy 拷贝部分排序的结果
sort 排序
stable_sort 稳定排序
二分法查找操作:
binary_search 判断范围中是否存在值等价于给定值的元素
equal_range 返回范围中值等于给定值的元素组成的子范围
lower_bound 返回指向范围中第一个值大于或等于给定值的元素的迭代器
upper_bound 返回指向范围中第一个值大于给定值的元素的迭代器
集合操作:
includes 判断一个集合是否是另一个集合的子集
inplace_merge 就绪合并
merge 合并
set_difference 获得两个集合的差集
set_intersection 获得两个集合的交集
set_symmetric_difference 获得两个集合的对称差
set_union 获得两个集合的并集
堆操作:
is_heap 检测给定范围是否满足堆结构
is_heap_untilC++11 检测给定范围中满足堆结构的最大子范围
make_heap 用给定范围构造出一个堆
pop_heap 从一个堆中删除最大的元素
push_heap 向堆中增加一个元素
sort_heap 将满足堆结构的范围排序
最大/最小操作:
is_permutationC++11 判断一个序列是否是另一个序列的一种排序
lexicographical_compare 比较两个序列的字典序
max 返回两个元素中值最大的元素
max_element 返回给定范围中值最大的元素
min 返回两个元素中值最小的元素
min_element 返回给定范围中值最小的元素
minmaxC++11 返回两个元素中值最大及最小的元素
minmax_elementC++11 返回给定范围中值最大及最小的元素
next_permutation 返回给定范围中的元素组成的下一个按字典序的排列
prev_permutation 返回给定范围中的元素组成的上一个按字典序的排列
Vector
初始化:
(1) vector a(10); //定义了10个整型元素的向量(尖括号中为元素类型名,它可以是任何合法的数据类型),但没有给出初值,其值是不确定的。
(2)vector a(10,1); //定义了10个整型元素的向量,且给出每个元素的初值为1
(3)vector a(b); //用b向量来创建a向量,整体复制性赋值
(4)vector a(b.begin(),b.begin+3); //定义了a值为b中第0个到第2个(共3个)元素
(5)int b[7]={1,2,3,4,5,9,8};
vector a(b,b+7); 或者vector a(b,&b[7])//从数组中获得初值;
函数:
(1)a.assign(b.begin(), b.begin()+3); //b为向量,将b的0~2个元素构成的向量赋给a
(2)a.assign(4,2); //是a只含4个元素,且每个元素为2
(3)a.back(); //返回a的最后一个元素
(4)a.front(); //返回a的第一个元素
(5)a[i]; //返回a的第i个元素,当且仅当a[i]存在2013-12-07
(6)a.clear(); //清空a中的元素
(7)a.empty(); //判断a是否为空,空则返回ture,不空则返回false
(8)a.pop_back(); //删除a向量的最后一个元素
(9)a.erase(a.begin()+1,a.begin()+3); //删除a中第1个(从第0个算起)到第2个元素,也就是说删除的元素从a.begin()+1算起(包括它)一直到a.begin()+ 3(不包括它)
(10)a.push_back(5); //在a的最后一个向量后插入一个元素,其值为5
(11)a.insert(a.begin()+1,5); //在a的第1个元素(从第0个算起)的位置插入数值5,如a为1,2,3,4,插入元素后为1,5,2,3,4
(12)a.insert(a.begin()+1,3,5); //在a的第1个元素(从第0个算起)的位置插入3个数,其值都为5
(13)a.insert(a.begin()+1,b+3,b+6); //b为数组,在a的第1个元素(从第0个算起)的位置插入b的第3个元素到第5个元素(不包括b+6),如b为1,2,3,4,5,9,8 ,插入元素后为1,4,5,9,2,3,4,5,9,8
(14)a.size(); //返回a中元素的个数;
(15)a.capacity(); //返回a在内存中总共可以容纳的元素个数
(16)a.resize(10); //将a的现有元素个数调至10个,多则删,少则补,其值随机
(17)a.resize(10,2); //将a的现有元素个数调至10个,多则删,少则补,其值为2
(18)a.reserve(100); //将a的容量(capacity)扩充至100,也就是说现在测试a.capacity();的时候返回值是100.这种操作只有在需要给a添加大量数据的时候才 显得有意义,因为这将避免内存多次容量扩充操作(当a的容量不足时电脑会自动扩容,当然这必然降低性能)
(19)a.swap(b); //b为向量,将a中的元素和b中的元素进行整体性交换
(20)a==b; //b为向量,向量的比较操作还有!=,>=,<=,>,<
访问vector的特殊方法
从现有向量中选择元素向向量中添加:
int a[6]={1,2,3,4,5,6};
vector b;
vector c(a,a+4);for(vector::iterator it=c.begin();it a;for(int i; in>>i)
a.push_back(i);
从向量中读取元素得方法:
int a[6]={1,2,3,4,5,6};
vector b(a,a+4);for(int i=0;i<=b.size()-1;i++)
cout< b(a,a+4);for(vector::iterator it=b.begin();it!=b.end();it++)
cout<<*it<<" ";
Vector的几种重要算法
1.
(1)sort(a.begin(),a.end()); //对a中的从a.begin()(包括它)到a.end()(不包括它)的元素进行从小到大排列
(2)reverse(a.begin(),a.end()); //对a中的从a.begin()(包括它)到a.end()(不包括它)的元素倒置,但不排列,如a中元素为1,3,2,4,倒置后为4,2,3,1
(3)copy(a.begin(),a.end(),b.begin()+1); //把a中的从a.begin()(包括它)到a.end()(不包括它)的元素复制到b中,从b.begin()+1的位置(包括它)开 始复制,覆盖掉原有元素
(4)find(a.begin(),a.end(),10); //在a中的从a.begin()(包括它)到a.end()(不包括它)的元素中查找10,若存在返回其在向量中的位置
2.(使用时注意)
vector::iterator it;//迭代器
int i;
初始化:
vectorv1; //定义空的vector
vectorv2(10); //产生大小为10的vector
vectorv3(10,-1); //产生大小为10,并且每个元素都是-1的vector
vectorv4(v3); //用一个vector产生一个vecotr
int arr[5]={1,2,3,4,5};
vectorv5(arr,&arr[5]); //以区间[beg;end)做为初值的vector
cout<a;
vectorb;
a.assign(4,2);//a只包含4个元素,且每个元素都为2;
cout<::size_type n=a.size();//Returns the number of elements in the vector.Member type size_type is an unsigned integral type.
cout<<"a.size:"<lst1; //创建空list
list lst2(5); //创建含有5个元素的list
listlst3(3,2); //创建含有3个元素的list
listlst4(lst2); //使用lst2初始化lst4
listlst5(lst2.begin(),lst2.end()); //同lst4
操作函数
listlst1; //创建空list
list lst2(5); //创建含有5个元素的list,每个元素都为0
listlst3(3,2); //创建含有3个元素的list,每个元素都为2
listlst4(lst2); //使用lst2初始化lst4
listlst5(lst2.begin(),lst2.end()); //声明一个列表,其元素的初始值来源于由区间所指定的序列中的元素,
list a;
list::iterator it1,it2;
赋值:
a.push_back(i);//push_back()是从list末端插入,而push_front是从头部插入
b.赋值 :a.push_front(i);
遍历:
for(it1=a.begin();it1!=a.end();++it1)
printf("%d ",*it1);
a的大小 : printf("\nsize:%d\n",a.size());// a的元素个数
a的最大容量: cout<::reverse_iterator it3;
双向链表末段: it3=a.rbegin();//返回逆向链表的第一个元素,即c链表的最后一个数据。
双向链表的头部: it3=a.rend();//返回逆向链表的最后一个元素的下一个位置,即c链表的第一个数据再往前的位置。
//使用pop_back()可以删掉尾部第一个元素,pop_front()可以删掉头部第一个元素。注意:list必须不为空,
//如果当list为空的时候调用pop_back()和pop_front()会使程序崩掉。
//使用前最好先a.empty();
删除:
a.pop_back();
a.pop_front();
赋值:
a.assign(3,1);//将a变成元素个数为3,值都为1的list
listb;
b.assign(a.begin(),a.end());//将b初始化,且和a相同 ,a.begin()和a.end()只能能++或者--
int ints[]={1,2,3,4};
a.assign(ints,ints+4);//利用数组初始化a
交换:
a.swap(b);//交换两个链表。a.swap(b)和swap(a, b),都可以完成a链表和b链表的交换。
转置:
reverse(b.begin(),b.end());
Empty:
if(a.empty()) {...;}
合并:
a.merge(b,less());//将b合并到a,less()(默认):a在前,b在后,greater则相反
//也可以用cmp ( bool mycomparison (double first, double second)
{ return ( int(first) 0 迭代器+n, n <0 迭代器-n。
it2++;
删除: a.erase(it1);//删除第5个元素(a从0开始)
it1=a.begin();
it2=a.begin();
advance(it1,4);
// a.erase(it1);//删除it1位置的元素
// 因为a.erase()是对地址进行操作,当执行这一步时,下面erase会爆炸
a.erase(++it2,it1);//删除a中it2到it1-1之间的元素
删除:
list::iterator it=++a.begin();
a.remove(1);// 删除链表中匹配num的元素。
a.remove_if(cmp_remove);//删除条件满足的元素,参数为自定义的回调函数。
for(it1=a.begin();it1!=a.end();++it1)
printf("%d ",*it1);
printf("\n");
去重
for(int i=1;i<5;i++) a.push_back(0);
a.unique();//删除相邻且重复的元素(保留一个)
for(it1=a.begin();it1!=a.end();++it1)
printf("%d ",*it1);
printf("\n");
排序
a.sort(cmp);//排序b不能用sort(a.begin(),a.end());
for(it1=a.begin();it1!=a.end();++it1)
printf("%d ",*it1);
printf("\n");
清空
a.clear();//删除链表中匹配num的元素。
Queue
queue a,b;
//queue没有迭代器!!!!!!!!!
插入
a.push(1);
删除
a.pop();
size
printf("%d\n",a.size());//返回值为 unsigned int
queueq; //创建一个int型空队列q
q.empty(); //判断队列是否为空,为空返回true
q.push(2); //将变量s从队尾入队
q.pop(); //将队头元素弹出
q.front(); // 只返回队头元素
q.back(); //只返回队尾元素
q.size(); // 返回队列中元素个数
Deque
(头文件deque)双端队列的操作 (可以在队头队尾进行入队出队操作)
//deque有迭代器!!!
deque dq; //创建一个数双端队列dq
dq.empty(); //判断队列是否为空,为空返回true
dq.push_front(3); //将s从队头入队
deque::iterator it;
it=dq.begin();
printf("%d\n",*it);
dq.push_back(4); //将s从队尾入队,和普通队列方式一样
dq.front(); //只返回队头元素
dq.back(); //只返回队尾元素
dq.pop_front(); //将队头元素弹出
dq.pop_back(); //将队尾元素弹出
dq.clear(); //将队列清空
虽然是自己写的,但是都忘了。